Integrate new configuration

This commit is contained in:
Daniel Salzman 2015-02-28 14:18:53 +01:00
parent 3542106549
commit b533bb4057
64 changed files with 1483 additions and 1212 deletions

View file

@ -1,89 +1,57 @@
#
# This is a sample of a minimal configuration file for Knot DNS.
#
# For exhaustive list of all options see man 5 knot.conf or refer to user manual.
#
system {
# Identity of the server (see RFC 4892).
identity on;
server:
# Identity of the server.
identity: "Knot DNS"
# Version of the server (see RFC 4892)
version on;
# Version of the server (automatic value).
version: ""
# User for running server
# May also specify user.group (e.g. knot.knot)
user knot.knot;
# Listening interfaces (all configured IPv4 and IPv6 interfaces).
listen: 0.0.0.0@53
listen: ::@53
# Directory for storing run-time data
# e.g. PID file and control sockets
# default: ${localstatedir}/run/knot, configured with --with-rundir
# rundir "@run_dir@";
}
remote:
- id: slave
address: 203.0.113.1@53
interfaces {
all_ipv4 {
address 0.0.0.0;
port 53;
}
all_ipv6 {
address [::];
port 53;
}
}
- id: master
address: 198.51.100.1@53
control {
# Default: knot.sock (relative to rundir)
listen-on "knot.sock";
acl:
- id: acl_slave
address: 203.0.113.1
action: xfer
# As an alternative, you can use an IPv4/v6 address and port
# Same syntax as for 'interfaces' items
# listen-on { address 127.0.0.1@5533; }
- id: acl_master
address: 198.51.100.1
action: notify
# Specifies ACL list for remote control
# Same syntax as for ACLs in zones
# List of remotes or groups delimited by comma
# Notice: keep in mind that ACLs bear no effect with UNIX sockets
# allow server0, admins;
}
template:
- id: default
storage: "@storage_dir@"
#remotes {
# master0 {
# address 198.51.100.1@53;
# }
# slave0 {
# address 203.0.113.1@53;
# }
#}
zone:
# Master zone.
- domain: example.com
file: "@storage_dir@/example.com.zone"
notify: slave
acl: acl_slave
zones {
# This is a default directory to place slave zone files, journals etc.
# default: ${localstatedir}/lib/knot, configured with --with-storage
# storage "@storage_dir@";
#
# Example master zone
# example.com {
# file "@config_dir@/example.com.zone";
# xfr-out slave0;
# notify-out slave0;
# }
#
# Example slave zone
# example.net {
# file "@storage_dir@/example.net.zone
# xfr-in master0;
# notify-in master0;
# }
}
# Slave zone.
- domain: example.net
file: "@storage_dir@/example.net.zone"
master: master
acl: acl_master
log {
syslog {
# Log info and more serious events to syslog
any info;
}
log:
# Log info and more serious events to syslog.
- to: syslog
any: info
# Log warnings, errors and criticals to stderr
stderr {
any warning;
}
}
# Log warnings, errors and criticals to stderr.
- to: stderr
any: warning

View file

@ -1,9 +1,9 @@
ACLOCAL_AMFLAGS = -I $(top_srcdir)/m4
SUBDIRS = zscanner dnssec dnstap .
lib_LTLIBRARIES = \
libknot-int.la \
libknot.la \
lib_LTLIBRARIES = \
libknot-int.la \
libknot.la \
libknot-yparser.la
noinst_LTLIBRARIES =
@ -54,9 +54,9 @@ nobase_libknot_int_la_HEADERS = \
libknot_yparser_ladir = $(includedir)
nobase_libknot_yparser_la_HEADERS = \
libknot/yparser/yparser.h \
libknot/yparser/ypformat.h \
libknot/yparser/ypscheme.h \
libknot/yparser/yparser.h \
libknot/yparser/ypformat.h \
libknot/yparser/ypscheme.h \
libknot/yparser/yptrafo.h
# dynamic: libknot internal sources
@ -85,11 +85,11 @@ libknot_int_la_SOURCES = \
$(nobase_libknot_int_la_HEADERS)
libknot_yparser_la_SOURCES = \
libknot/yparser/yparser.c \
libknot/yparser/ypbody.c \
libknot/yparser/ypformat.c \
libknot/yparser/ypscheme.c \
libknot/yparser/yptrafo.c \
libknot/yparser/yparser.c \
libknot/yparser/ypbody.c \
libknot/yparser/ypformat.c \
libknot/yparser/ypscheme.c \
libknot/yparser/yptrafo.c \
$(nobase_libknot_yparser_la_HEADERS)
# dynamic: libknot headers
@ -168,12 +168,12 @@ libknot_la_LIBADD = libknot-int.la dnssec/libdnssec.la zscanner/libzscanner.la
pkgconfig_DATA = libknot.pc libknot-int.pc
if !HAVE_LMDB
libknot_int_la_SOURCES += \
libknot/internal/namedb/mdb.c \
libknot/internal/namedb/midl.c \
libknot/internal/namedb/lmdb.h \
libknot_int_la_SOURCES += \
libknot/internal/namedb/mdb.c \
libknot/internal/namedb/midl.c \
libknot/internal/namedb/lmdb.h \
libknot/internal/namedb/midl.h
libknot_int_la_CPPFLAGS += \
libknot_int_la_CPPFLAGS += \
-I$(srcdir)/libknot/internal/namedb/
endif
@ -330,8 +330,8 @@ libknotd_la_CPPFLAGS = $(AM_CPPFLAGS) $(systemd_CFLAGS)
libknotd_la_LDFLAGS = $(AM_LDFLAGS) $(systemd_LIBS)
libknotd_la_LIBADD = libknot.la
knotd_LDADD = libknotd.la
knotc_LDADD = libknotd.la
knotd_LDADD = libknotd.la libknot-yparser.la
knotc_LDADD = libknotd.la libknot-yparser.la
####################################
# Optional Knot DNS Daemon modules #

View file

@ -20,7 +20,7 @@
#include <stdlib.h>
#include <unistd.h>
#include <sys/time.h>
#include <time.h> // strftime
#include <time.h>
#include <urcu.h>
#ifdef ENABLE_SYSTEMD
@ -165,11 +165,8 @@ int log_init()
{
/* Setup initial state. */
int ret = KNOT_EOK;
int emask = LOG_MASK(LOG_WARNING)|LOG_MASK(LOG_ERR)|LOG_MASK(LOG_CRIT);
int imask = LOG_MASK(LOG_INFO)|LOG_MASK(LOG_NOTICE);
/* Add debug messages. */
emask |= LOG_MASK(LOG_DEBUG);
int emask = LOG_MASK(LOG_CRIT) | LOG_MASK(LOG_ERR) | LOG_MASK(LOG_WARNING);
int imask = LOG_MASK(LOG_NOTICE) | LOG_MASK(LOG_INFO) | LOG_MASK(LOG_DEBUG);
/* Publish base log sink. */
struct log_sink *log = sink_setup(0);
@ -427,28 +424,6 @@ int log_msg_zone_str(int priority, const char *zone, const char *fmt, ...)
return result;
}
void hex_log(const char *data, int length)
{
int ptr = 0;
char lbuf[512]={0}; int llen = 0;
for (; ptr < length; ptr++) {
if (ptr > 0 && ptr % 16 == 0) {
lbuf[llen] = '\0';
log_msg(LOG_DEBUG, "%s\n", lbuf);
llen = 0;
}
int ret = snprintf(lbuf + llen, sizeof(lbuf) - llen, "0x%02x ",
(unsigned char)*(data + ptr));
if (ret < 0 || ret >= sizeof(lbuf) - llen) {
return;
}
llen += ret;
}
if (llen > 0) {
log_msg(LOG_DEBUG, "%s\n", lbuf);
}
}
int log_update_privileges(int uid, int gid)
{
for (unsigned i = 0; i < s_log->file_count; ++i) {
@ -460,13 +435,28 @@ int log_update_privileges(int uid, int gid)
return KNOT_EOK;
}
int log_reconfigure(const list_t *logs, void *data)
static logtype_t get_logtype(const char *logname)
{
assert(logname);
if (strcasecmp(logname, "syslog") == 0) {
return LOGT_SYSLOG;
} else if (strcasecmp(logname, "stderr") == 0) {
return LOGT_STDERR;
} else if (strcasecmp(logname, "stdout") == 0) {
return LOGT_STDOUT;
} else {
return LOGT_FILE;
}
}
int log_reconfigure(conf_t *conf, void *data)
{
// Data not used
UNUSED(data);
// Use defaults if no 'log' section is configured.
if (EMPTY_LIST(*logs)) {
if (conf_id_count(conf, C_LOG) == 0) {
log_close();
log_init();
return KNOT_EOK;
@ -474,13 +464,16 @@ int log_reconfigure(const list_t *logs, void *data)
// Find maximum log facility id
unsigned files = 0;
node_t *list_node = NULL;
WALK_LIST(list_node, *logs) {
conf_log_t* log = (conf_log_t*)list_node;
if (log->type == LOGT_FILE) {
conf_iter_t iter = conf_iter(conf, C_LOG);
while (iter.code == KNOT_EOK) {
conf_val_t id = conf_iter_id(conf, &iter);
if (get_logtype(conf_str(&id)) == LOGT_FILE) {
++files;
}
conf_iter_next(conf, &iter);
}
conf_iter_finish(conf, &iter);
// Initialize logsystem
struct log_sink *log = sink_setup(files);
@ -489,49 +482,46 @@ int log_reconfigure(const list_t *logs, void *data)
}
// Setup logs
list_node = NULL;
WALK_LIST(list_node, *logs) {
iter = conf_iter(conf, C_LOG);
while (iter.code == KNOT_EOK) {
conf_val_t id = conf_iter_id(conf, &iter);
const char *logname = conf_str(&id);
// Calculate offset
conf_log_t* facility_conf = (conf_log_t*)list_node;
int facility = facility_conf->type;
// Get facility.
int facility = get_logtype(logname);
if (facility == LOGT_FILE) {
facility = log_open_file(log, facility_conf->file);
facility = log_open_file(log, logname);
if (facility < 0) {
log_error("failed to open log, file '%s'",
facility_conf->file);
logname);
conf_iter_next(conf, &iter);
continue;
}
}
// Setup sources mapping
node_t *m = 0;
WALK_LIST(m, facility_conf->map) {
conf_val_t level_val;
unsigned level;
// Assign mapped level
conf_log_map_t *map = (conf_log_map_t*)m;
sink_levels_add(log, facility, map->source, map->prios);
}
// Set SERVER logging.
level_val = conf_id_get(conf, C_LOG, C_SERVER, &id);
level = conf_opt(&level_val);
sink_levels_add(log, facility, LOG_SERVER, level);
// Set ZONE logging.
level_val = conf_id_get(conf, C_LOG, C_ZONE, &id);
level = conf_opt(&level_val);
sink_levels_add(log, facility, LOG_ZONE, level);
// Set ANY logging.
level_val = conf_id_get(conf, C_LOG, C_ANY, &id);
level = conf_opt(&level_val);
sink_levels_add(log, facility, LOG_ANY, level);
conf_iter_next(conf, &iter);
}
conf_iter_finish(conf, &iter);
sink_publish(log);
return KNOT_EOK;
}
void log_free(conf_log_t *log)
{
if (!log) {
return;
}
free(log->file);
/* Free loglevel mapping. */
node_t *n = NULL, *nxt = NULL;
WALK_LIST_DELSAFE(n, nxt, log->map) {
free((conf_log_map_t*)n);
}
free(log);
}

View file

@ -39,9 +39,8 @@
#include <stdbool.h>
#include <assert.h>
#include "libknot/internal/lists.h"
#include "libknot/dname.h"
#include "knot/conf/conf.h"
/*! \brief Log facility types. */
typedef enum {
@ -61,25 +60,6 @@ typedef enum {
LOG_ANY = 7 /*!< Any module. */
} logsrc_t;
/*!
* \brief Mapping of loglevels to message sources.
*/
typedef struct conf_log_map {
node_t n;
int source; /*!< Log message source mask. */
int prios; /*!< Log priorities mask. */
} conf_log_map_t;
/*!
* \brief Log facility descriptor.
*/
typedef struct conf_log {
node_t n;
logtype_t type; /*!< Type of the log (SYSLOG/STDERR/FILE). */
char *file; /*!< Filename in case of LOG_FILE, else NULL. */
list_t map; /*!< Log levels mapping. */
} conf_log_t;
/*! \brief Format for timestamps in log files. */
#define KNOT_LOG_TIME_FORMAT "%Y-%m-%dT%H:%M:%S"
@ -172,8 +152,6 @@ int log_msg_zone(int priority, const knot_dname_t *zone, const char *fmt, ...)
int log_msg_zone_str(int priority, const char *zone, const char *fmt, ...)
__attribute__((format(printf, 3, 4)));
void hex_log(const char *data, int length);
/* Convenient logging. */
#define log_fatal(msg...) log_msg(LOG_CRIT, msg)
@ -215,9 +193,6 @@ int log_update_privileges(int uid, int gid);
* \retval KNOT_EINVAL on invalid parameters.
* \retval KNOT_ENOMEM out of memory error.
*/
int log_reconfigure(const list_t *logs, void *data);
/*! \brief Free log config. */
void log_free(conf_log_t *log);
int log_reconfigure(conf_t *conf, void *data);
/*! @} */

View file

@ -31,7 +31,6 @@
#include "libknot/libknot.h"
#include "knot/common/debug.h"
#include "knot/ctl/estimator.h"
#include "knot/ctl/process.h"
#include "knot/ctl/remote.h"
#include "knot/conf/conf.h"
#include "knot/server/tcp-handler.h"
@ -40,10 +39,9 @@
/*! \brief Controller flags. */
enum knotc_flag_t {
F_NULL = 0 << 0,
F_FORCE = 1 << 0,
F_VERBOSE = 1 << 1,
F_NOCONF = 1 << 2
F_NULL = 0,
F_FORCE = 1 << 0,
F_VERBOSE = 1 << 1
};
/*! \brief Check if flag is present. */
@ -52,45 +50,58 @@ static inline unsigned has_flag(unsigned flags, enum knotc_flag_t f)
return flags & f;
}
/*! \brief Callback arguments. */
typedef struct cmd_args {
struct sockaddr_storage *addr;
knot_tsig_key_t *key;
int argc;
char **argv;
unsigned flags;
const char *conf_db;
} cmd_args_t;
/*! \brief Callback prototype for command. */
typedef int (*knot_cmdf_t)(int argc, char *argv[], unsigned flags);
typedef int (*knot_cmdf_t)(cmd_args_t *args);
/*! \brief Command table item. */
typedef struct knot_cmd {
knot_cmdf_t cb;
int need_conf;
const char *name;
const char *params;
const char *desc;
} knot_cmd_t;
/* Forward decls. */
static int cmd_stop(int argc, char *argv[], unsigned flags);
static int cmd_reload(int argc, char *argv[], unsigned flags);
static int cmd_refresh(int argc, char *argv[], unsigned flags);
static int cmd_flush(int argc, char *argv[], unsigned flags);
static int cmd_status(int argc, char *argv[], unsigned flags);
static int cmd_zonestatus(int argc, char *argv[], unsigned flags);
static int cmd_checkconf(int argc, char *argv[], unsigned flags);
static int cmd_checkzone(int argc, char *argv[], unsigned flags);
static int cmd_memstats(int argc, char *argv[], unsigned flags);
static int cmd_signzone(int argc, char *argv[], unsigned flags);
static int cmd_stop(cmd_args_t *args);
static int cmd_reload(cmd_args_t *args);
static int cmd_refresh(cmd_args_t *args);
static int cmd_flush(cmd_args_t *args);
static int cmd_status(cmd_args_t *args);
static int cmd_zonestatus(cmd_args_t *args);
static int cmd_checkconf(cmd_args_t *args);
static int cmd_checkzone(cmd_args_t *args);
static int cmd_memstats(cmd_args_t *args);
static int cmd_signzone(cmd_args_t *args);
static int cmd_import(cmd_args_t *args);
static int cmd_export(cmd_args_t *args);
/*! \brief Table of remote commands. */
knot_cmd_t knot_cmd_tbl[] = {
{&cmd_stop, 0, "stop", "", "Stop server."},
{&cmd_reload, 0, "reload", "[<zone>...]", "Reload particular zones or reload whole\n"
" configuration and changed zones."},
{&cmd_refresh, 0, "refresh", "[<zone>...]", "Refresh slave zones. Flag '-f' forces retransfer\n"
" (zone(s) must be specified)."},
{&cmd_flush, 0, "flush", "[<zone>...]", "Flush journal and update zone files."},
{&cmd_status, 0, "status", "", "Check if server is running."},
{&cmd_zonestatus, 0, "zonestatus", "[<zone>...]", "Show status of configured zones."},
{&cmd_checkconf, 1, "checkconf", "", "Check current server configuration."},
{&cmd_checkzone, 1, "checkzone", "[<zone>...]", "Check zones."},
{&cmd_memstats, 1, "memstats", "[<zone>...]", "Estimate memory use for zones."},
{&cmd_signzone, 0, "signzone", "<zone>...", "Sign zones with available DNSSEC keys."},
{NULL, 0, NULL, NULL, NULL}
{&cmd_stop, "stop", "", "Stop server."},
{&cmd_reload, "reload", "[<zone>...]", "Reload particular zones or reload whole\n"
" configuration and changed zones."},
{&cmd_refresh, "refresh", "[<zone>...]", "Refresh slave zones. Flag '-f' forces retransfer\n"
" (zone(s) must be specified)."},
{&cmd_flush, "flush", "[<zone>...]", "Flush journal and update zone files."},
{&cmd_status, "status", "", "Check if server is running."},
{&cmd_zonestatus, "zonestatus", "[<zone>...]", "Show status of configured zones."},
{&cmd_checkconf, "checkconf", "", "Check current server configuration."},
{&cmd_checkzone, "checkzone", "[<zone>...]", "Check zones."},
{&cmd_memstats, "memstats", "[<zone>...]", "Estimate memory use for zones."},
{&cmd_signzone, "signzone", "<zone>...", "Sign zones with available DNSSEC keys."},
{&cmd_import, "import", "<filename>", "Import configuration database."},
{&cmd_export, "export", "<filename>", "Export configuration database."},
{NULL, NULL, NULL, NULL}
};
/*! \brief Print help. */
@ -99,17 +110,19 @@ void help(void)
printf("Usage: %sc [parameters] <action> [action_args]\n", PACKAGE_NAME);
printf("\nParameters:\n"
" -c, --config <file> Select configuration file.\n"
" -s, --server <server> Remote UNIX socket/IP address\n"
" (default %s).\n"
" (default %s)\n"
" -C, --confdb <dir> Select configuration database directory.\n"
" -s, --server <server> Remote UNIX socket/IP address.\n"
" (default %s)\n"
" -p, --port <port> Remote server port (only for IP).\n"
" -y, --key <[hmac:]name:key> Use key specified on the command line\n"
" (default algorithm is hmac-md5).\n"
" -y, --key <[hmac:]name:key> Use key specified on the command line.\n"
" (default algorithm is hmac-md5)\n"
" -k, --keyfile <file> Use key file (as in config section 'keys').\n"
" -f, --force Force operation - override some checks.\n"
" -v, --verbose Verbose mode - additional runtime information.\n"
" -V, --version Print %s server version.\n"
" -h, --help Print help and usage.\n",
RUN_DIR "/knot.sock", PACKAGE_NAME);
CONF_DEFAULT_FILE, RUN_DIR "/knot.sock", PACKAGE_NAME);
printf("\nActions:\n");
knot_cmd_t *c = knot_cmd_tbl;
while (c->name != NULL) {
@ -180,19 +193,13 @@ static int cmd_remote_reply(int c)
return ret;
}
static int cmd_remote(const char *cmd, uint16_t rrt, int argc, char *argv[])
static int cmd_remote(struct sockaddr_storage *addr, knot_tsig_key_t *key,
const char *cmd, uint16_t rrt, int argc, char *argv[])
{
int rc = 0;
/* Check remote address. */
conf_iface_t *r = conf()->ctl.iface;
if (!r || r->addr.ss_family == AF_UNSPEC) {
log_error("no remote address for '%s' configured", cmd);
return 1;
}
/* Make query. */
knot_pkt_t *pkt = remote_query(cmd, r->key);
knot_pkt_t *pkt = remote_query(cmd, key);
if (!pkt) {
log_warning("failed to prepare query for '%s'", cmd);
return 1;
@ -228,8 +235,9 @@ static int cmd_remote(const char *cmd, uint16_t rrt, int argc, char *argv[])
}
}
if (r->key) {
int res = remote_query_sign(pkt->wire, &pkt->size, pkt->max_size, r->key);
if (key) {
int res = remote_query_sign(pkt->wire, &pkt->size, pkt->max_size,
key);
if (res != KNOT_EOK) {
log_error("failed to sign the packet");
knot_pkt_free(&pkt);
@ -241,9 +249,9 @@ static int cmd_remote(const char *cmd, uint16_t rrt, int argc, char *argv[])
/* Connect to remote. */
char addr_str[SOCKADDR_STRLEN] = {0};
sockaddr_tostr(addr_str, sizeof(addr_str), &r->addr);
sockaddr_tostr(addr_str, sizeof(addr_str), addr);
int s = net_connected_socket(SOCK_STREAM, &r->addr, &r->via, 0);
int s = net_connected_socket(SOCK_STREAM, addr, NULL, 0);
if (s < 0) {
log_error("failed to connect to remote host '%s'", addr_str);
knot_pkt_free(&pkt);
@ -252,7 +260,8 @@ static int cmd_remote(const char *cmd, uint16_t rrt, int argc, char *argv[])
/* Wait for availability. */
struct pollfd pfd = { s, POLLOUT, 0 };
if (poll(&pfd, 1, conf()->max_conn_reply) != 1) {
conf_val_t val = conf_get(conf(), C_SRV, C_MAX_CONN_REPLY);
if (poll(&pfd, 1, conf_int(&val)) != 1) {
log_error("failed to connect to remote host '%s'", addr_str);
close(s);
knot_pkt_free(&pkt);
@ -418,7 +427,8 @@ int main(int argc, char **argv)
/* Parse command line arguments */
int c = 0, li = 0, rc = 0;
unsigned flags = F_NULL;
const char *config_fn = conf_find_default();
const char *config_fn = CONF_DEFAULT_FILE;
const char *config_db = NULL;
/* Remote server descriptor. */
const char *r_addr = NULL;
@ -433,6 +443,7 @@ int main(int argc, char **argv)
/* Long options. */
struct option opts[] = {
{"config", required_argument, 0, 'c' },
{"confdb", required_argument, 0, 'C' },
{"server", required_argument, 0, 's' },
{"port", required_argument, 0, 'p' },
{"key", required_argument, 0, 'y' },
@ -444,11 +455,14 @@ int main(int argc, char **argv)
{0, 0, 0, 0}
};
while ((c = getopt_long(argc, argv, "s:p:y:k:fc:vVh", opts, &li)) != -1) {
while ((c = getopt_long(argc, argv, "s:p:y:k:fc:C:vVh", opts, &li)) != -1) {
switch (c) {
case 'c':
config_fn = optarg;
break;
case 'C':
config_db = optarg;
break;
case 's':
r_addr = optarg;
break;
@ -509,44 +523,60 @@ int main(int argc, char **argv)
/* Command not found. */
if (!cmd->name) {
log_error("invalid command: '%s'", argv[optind]);
log_fatal("invalid command: '%s'", argv[optind]);
rc = 1;
goto exit;
}
/* Open config, create empty if not exists. */
if (conf_open(config_fn) != KNOT_EOK) {
s_config = conf_new("");
flags |= F_NOCONF;
}
/* Open configuration. */
conf_t *new_conf = NULL;
if (config_db == NULL) {
int ret = conf_new(&new_conf, conf_scheme, NULL);
if (ret != KNOT_EOK) {
log_fatal("failed to initialize configuration database "
"(%s)", knot_strerror(ret));
rc = 1;
goto exit;
}
/* Check if config file is required. */
if (has_flag(flags, F_NOCONF) && cmd->need_conf) {
log_error("failed to find a config file, refusing to continue");
rc = 1;
goto exit;
}
/* Import the configuration file. */
ret = conf_import(new_conf, config_fn, true);
if (ret != KNOT_EOK) {
log_fatal("failed to load configuration file '%s' (%s)",
config_fn, knot_strerror(ret));
rc = 1;
goto exit;
}
/* Create remote iface if not present in config. */
conf_iface_t *ctl_if = conf()->ctl.iface;
if (!ctl_if) {
ctl_if = malloc(sizeof(conf_iface_t));
memset(ctl_if, 0, sizeof(conf_iface_t));
conf()->ctl.iface = ctl_if;
/* Fill defaults. */
if (!r_addr) {
r_addr = RUN_DIR "/knot.sock";
} else if (r_port < 0) {
r_port = REMOTE_DPORT;
new_conf->filename = strdup(config_fn);
} else {
/* Open configuration database. */
int ret = conf_new(&new_conf, conf_scheme, config_db);
if (ret != KNOT_EOK) {
log_fatal("failed to open configuration database '%s' "
"(%s)", config_db, knot_strerror(ret));
rc = 1;
goto exit;
}
}
/* Install the key. */
if (r_key.name) {
ctl_if->key = &r_key;
/* Run post-open config operations. */
int res = conf_post_open(new_conf);
if (res != KNOT_EOK) {
log_fatal("failed to use configuration (%s)", knot_strerror(res));
conf_free(new_conf, false);
return EXIT_FAILURE;
}
conf_update(new_conf);
/* Get control address. */
conf_val_t listen_val = conf_get(conf(), C_CTL, C_LISTEN);
conf_val_t rundir_val = conf_get(conf(), C_SRV, C_RUNDIR);
char *rundir = conf_abs_path(&rundir_val, NULL);
struct sockaddr_storage addr = conf_addr(&listen_val, rundir);
free(rundir);
/* Override from command line. */
if (r_addr) {
/* Check for v6 address. */
@ -563,11 +593,11 @@ int main(int argc, char **argv)
family = AF_UNIX;
}
sockaddr_set(&ctl_if->addr, family, r_addr, sockaddr_port(&ctl_if->addr));
sockaddr_set(&addr, family, r_addr, sockaddr_port(&addr));
}
if (r_port > 0) {
sockaddr_port_set(&ctl_if->addr, r_port);
sockaddr_port_set(&addr, r_port);
}
/* Verbose mode. */
@ -576,102 +606,132 @@ int main(int argc, char **argv)
LOG_MASK(LOG_INFO) | LOG_MASK(LOG_DEBUG));
}
cmd_args_t args = {
&addr,
r_key.name != NULL ? &r_key : NULL,
argc - optind - 1,
argv + optind + 1,
flags,
config_db
};
/* Execute command. */
dnssec_crypto_init();
rc = cmd->cb(argc - optind - 1, argv + optind + 1, flags);
rc = cmd->cb(&args);
dnssec_crypto_cleanup();
exit:
/* Finish */
knot_tsig_key_free(&r_key);
conf_free(conf(), false);
log_close();
return rc;
}
static int cmd_stop(int argc, char *argv[], unsigned flags)
static int cmd_stop(cmd_args_t *args)
{
UNUSED(argc);
UNUSED(argv);
UNUSED(flags);
if (argc > 0) {
if (args->argc > 0) {
printf("command does not take arguments\n");
return KNOT_EINVAL;
}
return cmd_remote("stop", KNOT_RRTYPE_TXT, 0, NULL);
return cmd_remote(args->addr, args->key, "stop", KNOT_RRTYPE_TXT,
0, NULL);
}
static int cmd_reload(int argc, char *argv[], unsigned flags)
static int cmd_reload(cmd_args_t *args)
{
UNUSED(flags);
return cmd_remote("reload", KNOT_RRTYPE_NS, argc, argv);
return cmd_remote(args->addr, args->key, "reload", KNOT_RRTYPE_NS,
args->argc, args->argv);
}
static int cmd_refresh(int argc, char *argv[], unsigned flags)
static int cmd_refresh(cmd_args_t *args)
{
UNUSED(flags);
const char *action = (args->flags & F_FORCE) ? "retransfer" : "refresh";
if (flags & F_FORCE) {
return cmd_remote("retransfer", KNOT_RRTYPE_NS, argc, argv);
} else {
return cmd_remote("refresh", KNOT_RRTYPE_NS, argc, argv);
}
return cmd_remote(args->addr, args->key, action, KNOT_RRTYPE_NS,
args->argc, args->argv);
}
static int cmd_flush(int argc, char *argv[], unsigned flags)
static int cmd_flush(cmd_args_t *args)
{
UNUSED(flags);
return cmd_remote("flush", KNOT_RRTYPE_NS, argc, argv);
return cmd_remote(args->addr, args->key, "flush", KNOT_RRTYPE_NS,
args->argc, args->argv);
}
static int cmd_status(int argc, char *argv[], unsigned flags)
static int cmd_status(cmd_args_t *args)
{
UNUSED(argv);
UNUSED(flags);
if (argc > 0) {
if (args->argc > 0) {
printf("command does not take arguments\n");
return KNOT_EINVAL;
}
return cmd_remote("status", KNOT_RRTYPE_TXT, 0, NULL);
return cmd_remote(args->addr, args->key, "status", KNOT_RRTYPE_TXT,
0, NULL);
}
static int cmd_zonestatus(int argc, char *argv[], unsigned flags)
static int cmd_zonestatus(cmd_args_t *args)
{
UNUSED(flags);
return cmd_remote("zonestatus", KNOT_RRTYPE_NS, argc, argv);
return cmd_remote(args->addr, args->key, "zonestatus", KNOT_RRTYPE_NS,
args->argc, args->argv);
}
static int cmd_signzone(int argc, char *argv[], unsigned flags)
static int cmd_signzone(cmd_args_t *args)
{
return cmd_remote("signzone", KNOT_RRTYPE_NS, argc, argv);
return cmd_remote(args->addr, args->key, "signzone", KNOT_RRTYPE_NS,
args->argc, args->argv);
}
static int cmd_checkconf(int argc, char *argv[], unsigned flags)
static int cmd_import(cmd_args_t *args)
{
UNUSED(argc);
UNUSED(argv);
UNUSED(flags);
if (args->argc != 1) {
printf("command takes one argument\n");
return KNOT_EINVAL;
}
if (!(args->flags & F_FORCE)) {
printf("use force option to import/replace config DB\n");
return KNOT_EINVAL;
}
conf_t *new_conf = NULL;
int ret = conf_new(&new_conf, conf_scheme, args->conf_db);
if (ret != KNOT_EOK) {
printf("failed to open configuration (%s)", args->conf_db);
return ret;
}
ret = conf_import(new_conf, args->argv[0], true);
if (ret != KNOT_EOK) {
printf("failed to import configuration (%s)", args->argv[0]);
conf_free(new_conf, false);
return ret;
}
return KNOT_EOK;
}
static int cmd_export(cmd_args_t *args)
{
if (args->argc != 1) {
printf("command takes one argument\n");
return KNOT_EINVAL;
}
return conf_export(conf(), args->argv[0], YP_SNONE);
}
static int cmd_checkconf(cmd_args_t *args)
{
UNUSED(args);
log_info("configuration is valid");
return 0;
}
static bool fetch_zone(int argc, char *argv[], conf_zone_t *zone)
static bool fetch_zone(int argc, char *argv[], const knot_dname_t *name)
{
/* Convert zone name to dname */
knot_dname_t *zone_name = knot_dname_from_str_alloc(zone->name);
if (zone_name == NULL) {
return false;
}
(void)knot_dname_to_lower(zone_name);
bool found = false;
int i = 0;
@ -681,77 +741,61 @@ static bool fetch_zone(int argc, char *argv[], conf_zone_t *zone)
if (arg_name != NULL) {
(void)knot_dname_to_lower(arg_name);
found = knot_dname_is_equal(zone_name, arg_name);
found = knot_dname_is_equal(name, arg_name);
}
i++;
knot_dname_free(&arg_name, NULL);
}
knot_dname_free(&zone_name, NULL);
return found;
}
static int cmd_checkzone(int argc, char *argv[], unsigned flags)
static int cmd_checkzone(cmd_args_t *args)
{
UNUSED(flags);
/* Zone checking */
int rc = 0;
/* Generate databases for all zones */
const bool sorted = false;
hattrie_iter_t *z_iter = hattrie_iter_begin(conf()->zones, sorted);
if (z_iter == NULL) {
return KNOT_ERROR;
}
for (; !hattrie_iter_finished(z_iter); hattrie_iter_next(z_iter)) {
conf_zone_t *zone = (conf_zone_t *)*hattrie_iter_val(z_iter);
conf_iter_t iter = conf_iter(conf(), C_ZONE);
while (iter.code == KNOT_EOK) {
conf_val_t id = conf_iter_id(conf(), &iter);
/* Fetch zone */
int zone_match = fetch_zone(argc, argv, zone);
if (!zone_match && argc > 0) {
conf_free_zone(zone);
int zone_match = fetch_zone(args->argc, args->argv, conf_dname(&id));
if (!zone_match && args->argc > 0) {
continue;
}
/* Create zone loader context. */
zone_contents_t *loaded_zone = zone_load_contents(zone);
zone_contents_t *loaded_zone = zone_load_contents(conf(), conf_dname(&id));
if (loaded_zone == NULL) {
rc = 1;
continue;
}
log_zone_str_info(zone->name, "zone is valid");
log_zone_info(conf_dname(&id), "zone is valid");
zone_contents_deep_free(&loaded_zone);
conf_iter_next(conf(), &iter);
}
hattrie_iter_free(z_iter);
conf_iter_finish(conf(), &iter);
return rc;
}
static int cmd_memstats(int argc, char *argv[], unsigned flags)
static int cmd_memstats(cmd_args_t *args)
{
UNUSED(flags);
/* Zone checking */
double total_size = 0;
/* Generate databases for all zones */
const bool sorted = false;
hattrie_iter_t *z_iter = hattrie_iter_begin(conf()->zones, sorted);
if (z_iter == NULL) {
return KNOT_ERROR;
}
for (; !hattrie_iter_finished(z_iter); hattrie_iter_next(z_iter)) {
conf_zone_t *zone = (conf_zone_t *)*hattrie_iter_val(z_iter);
conf_iter_t iter = conf_iter(conf(), C_ZONE);
while (iter.code == KNOT_EOK) {
conf_val_t id = conf_iter_id(conf(), &iter);
/* Fetch zone */
int zone_match = fetch_zone(argc, argv, zone);
if (!zone_match && argc > 0) {
conf_free_zone(zone);
int zone_match = fetch_zone(args->argc, args->argv, conf_dname(&id));
if (!zone_match && args->argc > 0) {
continue;
}
@ -772,24 +816,35 @@ static int cmd_memstats(int argc, char *argv[], unsigned flags)
}
/* Create zone scanner. */
zs_scanner_t *zs = zs_scanner_create(zone->name,
char *zone_name = knot_dname_to_str_alloc(conf_dname(&id));
if (zone_name == NULL) {
log_error("not enough memory");
hattrie_free(est.node_table);
break;
}
zs_scanner_t *zs = zs_scanner_create(zone_name,
KNOT_CLASS_IN, 3600,
estimator_rrset_memsize_wrap,
process_error,
&est);
free(zone_name);
if (zs == NULL) {
log_zone_str_error(zone->name, "failed to load zone");
log_zone_error(conf_dname(&id), "failed to load zone");
hattrie_free(est.node_table);
conf_iter_next(conf(), &iter);
continue;
}
/* Do a parser run, but do not actually create the zone. */
int ret = zs_scanner_parse_file(zs, zone->file);
char *zonefile = conf_zonefile(conf(), conf_dname(&id));
int ret = zs_scanner_parse_file(zs, zonefile);
free(zonefile);
if (ret != 0) {
log_zone_str_error(zone->name, "failed to parse zone");
log_zone_error(conf_dname(&id), "failed to parse zone");
hattrie_apply_rev(est.node_table, estimator_free_trie_node, NULL);
hattrie_free(est.node_table);
zs_scanner_free(zs);
conf_iter_next(conf(), &iter);
continue;
}
@ -807,15 +862,15 @@ static int cmd_memstats(int argc, char *argv[], unsigned flags)
est.htable_size +
malloc_size) * ESTIMATE_MAGIC) / (1024.0 * 1024.0);
log_zone_str_info(zone->name, "%zu RRs, used memory estimation is %zu MB",
est.record_count, (size_t)zone_size);
log_zone_info(conf_dname(&id), "%zu RRs, used memory estimation is %zu MB",
est.record_count, (size_t)zone_size);
zs_scanner_free(zs);
total_size += zone_size;
conf_free_zone(zone);
conf_iter_next(conf(), &iter);
}
hattrie_iter_free(z_iter);
conf_iter_finish(conf(), &iter);
if (argc == 0) { // for all zones
if (args->argc == 0) { // for all zones
log_info("estimated memory consumption for all zones is %zu MB",
(size_t)total_size);
}

View file

@ -21,36 +21,38 @@
#include <string.h>
#include <signal.h>
#include <grp.h>
#include <unistd.h>
#include <assert.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/types.h>
#include <pwd.h>
#include <urcu.h>
#include "libknot/internal/mem.h"
#include "libknot/libknot.h"
#include "knot/ctl/process.h"
#include "knot/conf/conf.h"
#include "knot/common/log.h"
#include "libknot/errcode.h"
#include "libknot/internal/mem.h"
#include "libknot/libknot.h"
#define LOCK_FILE "knot.lock"
char* pid_filename()
{
rcu_read_lock();
/* Read configuration. */
char* ret = NULL;
if (conf()) {
if (conf()->pidfile != NULL)
ret = strdup(conf()->pidfile);
else if (conf()->rundir != NULL)
ret = strcdup(conf()->rundir, "/knot.pid");
}
conf_val_t val = conf_get(conf(), C_SRV, C_RUNDIR);
char *rundir = conf_abs_path(&val, NULL);
val = conf_get(conf(), C_SRV, C_PIDFILE);
char *pidfile = conf_abs_path(&val, rundir);
rcu_read_unlock();
return ret;
if (rundir != NULL) {
free(rundir);
return pidfile;
} else {
return NULL;
}
}
pid_t pid_read(const char* fn)
@ -171,35 +173,39 @@ int proc_update_privileges(int uid, int gid)
}
}
/* Check storage writeability. */
int ret = KNOT_EOK;
const bool sorted = false;
hattrie_iter_t *z_iter = hattrie_iter_begin(conf()->zones, sorted);
if (z_iter == NULL) {
return KNOT_ERROR;
}
for (; !hattrie_iter_finished(z_iter); hattrie_iter_next(z_iter)) {
conf_zone_t *zone = (conf_zone_t *)*hattrie_iter_val(z_iter);
char *lfile = strcdup(zone->storage, "/knot.lock");
/* Check storage writability. */
conf_iter_t iter = conf_iter(conf(), C_ZONE);
while (iter.code == KNOT_EOK) {
conf_val_t id = conf_iter_id(conf(), &iter);
conf_val_t val = conf_zone_get(conf(), C_STORAGE, conf_dname(&id));
char *storage = conf_abs_path(&val, NULL);
if (storage == NULL) {
conf_iter_finish(conf(), &iter);
return KNOT_ENOMEM;
}
char *lfile = sprintf_alloc("%s/%s", storage, LOCK_FILE);
assert(lfile != NULL);
FILE* fp = fopen(lfile, "w");
FILE *fp = fopen(lfile, "w");
if (fp == NULL) {
log_warning("storage directory '%s' is not writable",
zone->storage);
ret = KNOT_EACCES;
log_error("storage directory '%s' is not writable",
storage);
free(lfile);
free(storage);
conf_iter_finish(conf(), &iter);
return KNOT_EACCES;
} else {
fclose(fp);
unlink(lfile);
}
free(lfile);
free(storage);
if (ret != KNOT_EOK) {
break;
}
conf_iter_next(conf(), &iter);
}
hattrie_iter_free(z_iter);
conf_iter_finish(conf(), &iter);
return ret;
return KNOT_EOK;
}
char *pid_check_and_create()

View file

@ -16,6 +16,7 @@
#include <assert.h>
#include <sys/stat.h>
#include <urcu.h>
#include "dnssec/random.h"
#include "knot/common/debug.h"
@ -172,7 +173,11 @@ static int remote_zone_refresh(zone_t *zone, remote_cmdargs_t *a)
{
UNUSED(a);
if (zone_master(zone) == NULL) {
rcu_read_lock();
bool is_master = zone_is_master(zone);
rcu_read_unlock();
if (is_master) {
return KNOT_EINVAL;
}
@ -194,7 +199,11 @@ static int remote_zone_retransfer(zone_t *zone, remote_cmdargs_t *a)
{
UNUSED(a);
if (zone_master(zone) == NULL) {
rcu_read_lock();
bool is_master = zone_is_master(zone);
rcu_read_unlock();
if (is_master) {
return KNOT_EINVAL;
}
@ -221,7 +230,12 @@ static int remote_zone_sign(zone_t *zone, remote_cmdargs_t *a)
{
UNUSED(a);
if (zone == NULL || !zone->conf->dnssec_enable) {
rcu_read_lock();
conf_val_t val = conf_zone_get(conf(), C_DNSSEC_ENABLE, zone->name);
bool dnssec_enable = conf_bool(&val);
rcu_read_unlock();
if (zone == NULL || !dnssec_enable) {
return KNOT_EINVAL;
}
@ -342,15 +356,22 @@ static int remote_zonestatus(zone_t *zone, remote_cmdargs_t *a)
/* Prepare zone info. */
char buf[512] = { '\0' };
char dnssec_buf[128] = { '\0' };
char *zone_name = knot_dname_to_str_alloc(zone->name);
conf_val_t val = conf_zone_get(conf(), C_DNSSEC_ENABLE, zone->name);
bool dnssec_enable = conf_bool(&val);
bool is_master = zone_is_master(zone);
int n = snprintf(buf, sizeof(buf),
"%s\ttype=%s | serial=%u | %s %s | %s %s\n",
zone->conf->name,
zone_master(zone) ? "slave" : "master",
zone_name,
is_master ? "master" : "slave",
serial,
next_name,
when,
zone->conf->dnssec_enable ? "automatic DNSSEC, resigning at:" : "DNSSEC signing disabled",
zone->conf->dnssec_enable ? dnssec_info(zone, dnssec_buf, sizeof(dnssec_buf)) : "");
dnssec_enable ? "automatic DNSSEC, resigning at:" : "DNSSEC signing disabled",
dnssec_enable ? dnssec_info(zone, dnssec_buf, sizeof(dnssec_buf)) : "");
free(zone_name);
if (n < 0 || n >= sizeof(buf)) {
return KNOT_ESPACE;
}
@ -495,21 +516,21 @@ static int remote_senderr(int c, uint8_t *qbuf, size_t buflen)
/* Public APIs. */
int remote_bind(conf_iface_t *desc)
int remote_bind(struct sockaddr_storage *addr)
{
if (desc == NULL) {
if (addr == NULL) {
return KNOT_EINVAL;
}
char addr_str[SOCKADDR_STRLEN] = {0};
sockaddr_tostr(addr_str, sizeof(addr_str), &desc->addr);
char addr_str[SOCKADDR_STRLEN] = { 0 };
sockaddr_tostr(addr_str, sizeof(addr_str), addr);
log_info("remote control, binding to '%s'", addr_str);
/* Create new socket. */
mode_t old_umask = umask(KNOT_CTL_SOCKET_UMASK);
int sock = net_bound_socket(SOCK_STREAM, &desc->addr, 0);
int sock = net_bound_socket(SOCK_STREAM, addr, 0);
if (sock == KNOT_EADDRNOTAVAIL) {
sock = net_bound_socket(SOCK_STREAM, &desc->addr, NET_BIND_NONLOCAL);
sock = net_bound_socket(SOCK_STREAM, addr, NET_BIND_NONLOCAL);
if (sock >= 0) {
log_warning("remote control, address '%s' is not available",
addr_str);
@ -533,16 +554,16 @@ int remote_bind(conf_iface_t *desc)
return sock;
}
int remote_unbind(conf_iface_t *desc, int sock)
int remote_unbind(struct sockaddr_storage *addr, int sock)
{
if (desc == NULL || sock < 0) {
if (addr == NULL || sock < 0) {
return KNOT_EINVAL;
}
/* Remove control socket file. */
if (desc->addr.ss_family == AF_UNIX) {
char addr_str[SOCKADDR_STRLEN] = {0};
sockaddr_tostr(addr_str, sizeof(addr_str), &desc->addr);
if (addr->ss_family == AF_UNIX) {
char addr_str[SOCKADDR_STRLEN] = { 0 };
sockaddr_tostr(addr_str, sizeof(addr_str), addr);
unlink(addr_str);
}
@ -852,7 +873,7 @@ static int zones_verify_tsig_query(const knot_pkt_t *query,
return ret;
}
int remote_process(server_t *s, conf_iface_t *ctl_if, int sock,
int remote_process(server_t *s, struct sockaddr_storage *ctl_addr, int sock,
uint8_t* buf, size_t buflen)
{
knot_pkt_t *pkt = knot_pkt_new(buf, buflen, NULL);
@ -876,40 +897,38 @@ int remote_process(server_t *s, conf_iface_t *ctl_if, int sock,
/* Parse packet and answer if OK. */
int ret = remote_parse(pkt);
if (ret == KNOT_EOK && ctl_if->addr.ss_family != AF_UNIX) {
/* Check ACL list. */
char addr_str[SOCKADDR_STRLEN] = {0};
if (ret == KNOT_EOK && ctl_addr->ss_family != AF_UNIX) {
char addr_str[SOCKADDR_STRLEN] = { 0 };
sockaddr_tostr(addr_str, sizeof(addr_str), &ss);
knot_tsig_key_t *tsig_key = NULL;
const knot_dname_t *tsig_name = NULL;
/* Prepare tsig parameters. */
knot_tsig_key_t tsig = { NULL };
if (pkt->tsig_rr) {
tsig_name = pkt->tsig_rr->owner;
tsig.name = pkt->tsig_rr->owner;
tsig.algorithm = knot_tsig_rdata_alg(pkt->tsig_rr);
}
conf_iface_t *match = acl_find(&conf()->ctl.allow, &ss, tsig_name);
uint16_t ts_rc = 0;
uint16_t ts_trc = 0;
uint64_t ts_tmsigned = 0;
if (match == NULL) {
/* Check ACL. */
rcu_read_lock();
conf_val_t acl = conf_get(conf(), C_CTL, C_ACL);
bool allowed = acl_allowed(&acl, ACL_ACTION_CNTL, &ss, &tsig);
rcu_read_unlock();
if (!allowed) {
log_warning("remote control, denied '%s', "
"no matching ACL", addr_str);
remote_senderr(client, pkt->wire, pkt->size);
ret = KNOT_EACCES;
goto finish;
} else {
tsig_key = match->key;
}
/* Check TSIG. */
if (tsig_key) {
if (pkt->tsig_rr == NULL) {
log_warning("remote control, denied '%s', "
"key required", addr_str);
remote_senderr(client, pkt->wire, pkt->size);
ret = KNOT_EACCES;
goto finish;
}
ret = zones_verify_tsig_query(pkt, tsig_key, &ts_rc,
if (tsig.name != NULL) {
uint16_t ts_rc = 0;
uint16_t ts_trc = 0;
uint64_t ts_tmsigned = 0;
ret = zones_verify_tsig_query(pkt, &tsig, &ts_rc,
&ts_trc, &ts_tmsigned);
if (ret != KNOT_EOK) {
log_warning("remote control, denied '%s', "

View file

@ -26,37 +26,37 @@
#pragma once
#include "knot/conf/conf.h"
#include "libknot/packet/pkt.h"
#include "libknot/rrset.h"
#include "libknot/dnssec/key.h"
#include "knot/server/server.h"
/*! \brief Default remote control tool port. */
#define REMOTE_DPORT 5533
/*! \brief Default connection control parameters. */
#define REMOTE_PORT 5533
#define REMOTE_SOCKET "knot.sock"
/*!
* \brief Bind RC interface according to configuration.
* \brief Bind RC interface.
*
* \param desc Interface descriptor (address, port).
* \param addr Interface descriptor (address, port).
*
* \retval socket if passed.
* \retval knot_error else.
*/
int remote_bind(conf_iface_t *desc);
int remote_bind(struct sockaddr_storage *addr);
/*!
* \brief Unbind from RC interface and close socket.
*
* \note Breaks all pending connections.
*
* \param desc Interface descriptor (address, port).
* \param addr Interface descriptor (address, port).
* \param socket Interface socket
*
* \retval KNOT_EOK on success.
* \retval knot_error else.
*/
int remote_unbind(conf_iface_t *desc, int sock);
int remote_unbind(struct sockaddr_storage *addr, int sock);
/*!
* \brief Poll new events on RC socket.
@ -112,7 +112,7 @@ int remote_answer(int sock, server_t *s, knot_pkt_t *pkt);
* \note This should be used as a high-level API for workers.
*
* \param s Server instance.
* \param ctl_if Control interface.
* \param ctl_addr Control interface address.
* \param sock RC interface socket.
* \param buf Buffer for commands/responses.
* \param buflen Maximum buffer size.
@ -120,7 +120,7 @@ int remote_answer(int sock, server_t *s, knot_pkt_t *pkt);
* \retval KNOT_EOK on success.
* \retval knot_error else.
*/
int remote_process(server_t *s, conf_iface_t *ctl_if, int sock,
int remote_process(server_t *s, struct sockaddr_storage *ctl_addr, int sock,
uint8_t* buf, size_t buflen);
/* Functions for creating RC packets. */

View file

@ -21,9 +21,6 @@
#include "knot/zone/contents.h"
#include "libknot/rrtype/soa.h"
#define MINIMAL_RRSIG_LIFETIME (3 * 60 * 60)
#define DEFAULT_RRSIG_LIFETIME (30 * 24 * 60 * 60)
static uint32_t zone_soa_min_ttl(const zone_contents_t *zone)
{
knot_rrset_t soa = node_rrset(zone->apex, KNOT_RRTYPE_SOA);
@ -47,16 +44,11 @@ void update_policy_from_zone(dnssec_kasp_policy_t *policy,
policy->zone_maximal_ttl = 0; // TODO
}
void set_default_policy(dnssec_kasp_policy_t *policy, const conf_zone_t *config,
void set_default_policy(dnssec_kasp_policy_t *policy,
const zone_contents_t *zone)
{
if (config->sig_lifetime <= 0) {
policy->rrsig_lifetime = DEFAULT_RRSIG_LIFETIME;
} else if (config->sig_lifetime < MINIMAL_RRSIG_LIFETIME) {
policy->rrsig_lifetime = MINIMAL_RRSIG_LIFETIME;
} else {
policy->rrsig_lifetime = config->sig_lifetime;
}
conf_val_t val = conf_zone_get(conf(), C_SIG_LIFETIME, zone->apex->owner);
policy->rrsig_lifetime = conf_int(&val);
policy->rrsig_refresh_before = policy->rrsig_lifetime / 10;
policy->algorithm = 0;
policy->propagation_delay = 0;

View file

@ -29,5 +29,5 @@ void update_policy_from_zone(dnssec_kasp_policy_t *policy,
/*!
* \brief Set default DNSSEC policy for zone without assigned policy.
*/
void set_default_policy(dnssec_kasp_policy_t *policy, const conf_zone_t *config,
void set_default_policy(dnssec_kasp_policy_t *policy,
const zone_contents_t *zone);

View file

@ -38,14 +38,28 @@ static bool has_policy(const kdnssec_ctx_t *ctx)
return ctx && ctx->policy && ctx->policy->name;
}
static int sign_init(const zone_contents_t *zone, const conf_zone_t *config,
int flags, kdnssec_ctx_t *ctx)
static int sign_init(const zone_contents_t *zone, int flags, kdnssec_ctx_t *ctx)
{
assert(zone);
assert(config);
assert(ctx);
int r = kdnssec_ctx_init(ctx, config->dnssec_keydir, config->name);
const knot_dname_t *zone_name = zone->apex->owner;
conf_val_t val = conf_zone_get(conf(), C_STORAGE, zone_name);
char *storage = conf_abs_path(&val, NULL);
val = conf_zone_get(conf(), C_DNSSEC_KEYDIR, zone_name);
char *keydir = conf_abs_path(&val, storage);
free(storage);
char *zone_name_str = knot_dname_to_str_alloc(zone_name);
if (zone_name_str == NULL) {
free(keydir);
return KNOT_ENOMEM;
}
int r = kdnssec_ctx_init(ctx, keydir, zone_name_str);
free(zone_name_str);
free(keydir);
if (r != KNOT_EOK) {
return r;
}
@ -55,7 +69,7 @@ static int sign_init(const zone_contents_t *zone, const conf_zone_t *config,
if (has_policy(ctx)) {
update_policy_from_zone(ctx->policy, zone);
} else {
set_default_policy(ctx->policy, config, zone);
set_default_policy(ctx->policy, zone);
}
ctx->policy->nsec3_enabled = knot_is_nsec3_enabled(zone); // TODO: temporary
@ -70,7 +84,8 @@ static int sign_init(const zone_contents_t *zone, const conf_zone_t *config,
if (flags & ZONE_SIGN_KEEP_SOA_SERIAL) {
ctx->new_serial = ctx->old_serial;
} else {
ctx->new_serial = serial_next(ctx->old_serial, config->serial_policy);
val = conf_zone_get(conf(), C_SERIAL_POLICY, zone_name);
ctx->new_serial = serial_next(ctx->old_serial, conf_opt(&val));
}
return KNOT_EOK;
@ -162,11 +177,10 @@ static uint32_t schedule_next(kdnssec_ctx_t *kctx, const zone_keyset_t *keyset,
return next;
}
int knot_dnssec_zone_sign(zone_contents_t *zone, const conf_zone_t *config,
changeset_t *out_ch, zone_sign_flags_t flags,
uint32_t *refresh_at)
int knot_dnssec_zone_sign(zone_contents_t *zone, changeset_t *out_ch,
zone_sign_flags_t flags, uint32_t *refresh_at)
{
if (!zone || !config || !out_ch || !refresh_at) {
if (!zone || !out_ch || !refresh_at) {
return KNOT_EINVAL;
}
@ -177,7 +191,7 @@ int knot_dnssec_zone_sign(zone_contents_t *zone, const conf_zone_t *config,
// signing pipeline
result = sign_init(zone, config, flags, &ctx);
result = sign_init(zone, flags, &ctx);
if (result != KNOT_EOK) {
log_zone_error(zone_name, "DNSSEC, failed to initialize (%s)",
knot_strerror(result));
@ -245,7 +259,6 @@ done:
}
int knot_dnssec_sign_changeset(const zone_contents_t *zone,
conf_zone_t *config,
const changeset_t *in_ch,
changeset_t *out_ch,
uint32_t *refresh_at)
@ -261,7 +274,7 @@ int knot_dnssec_sign_changeset(const zone_contents_t *zone,
// signing pipeline
result = sign_init(zone, config, ZONE_SIGN_KEEP_SOA_SERIAL, &ctx);
result = sign_init(zone, ZONE_SIGN_KEEP_SOA_SERIAL, &ctx);
if (result != KNOT_EOK) {
log_zone_error(zone_name, "DNSSEC, failed to initialize (%s)",
knot_strerror(result));

View file

@ -44,22 +44,19 @@ typedef enum zone_sign_flags zone_sign_flags_t;
* and NSEC(3) records will not be changed.
*
* \param zone Zone contents to be signed.
* \param zone_config Zone/DNSSEC configuration.
* \param out_ch New records will be added to this changeset.
* \param flags Zone signing flags.
* \param refresh_at Signature refresh time of the oldest signature in zone.
*
* \return Error code, KNOT_EOK if successful.
*/
int knot_dnssec_zone_sign(zone_contents_t *zone, const conf_zone_t *zone_config,
changeset_t *out_ch, zone_sign_flags_t flags,
uint32_t *refresh_at);
int knot_dnssec_zone_sign(zone_contents_t *zone, changeset_t *out_ch,
zone_sign_flags_t flags, uint32_t *refresh_at);
/*!
* \brief Sign changeset created by DDNS or zone-diff.
*
* \param zone Zone contents to be signed.
* \param zone_config Zone/DNSSEC configuration.
* \param in_ch Changeset created bvy DDNS or zone-diff
* \param out_ch New records will be added to this changeset.
* \param refresh_at Signature refresh time of the new signatures.
@ -67,7 +64,6 @@ int knot_dnssec_zone_sign(zone_contents_t *zone, const conf_zone_t *zone_config,
* \return Error code, KNOT_EOK if successful.
*/
int knot_dnssec_sign_changeset(const zone_contents_t *zone,
conf_zone_t *zone_config,
const changeset_t *in_ch,
changeset_t *out_ch,
uint32_t *refresh_at);

View file

@ -14,13 +14,14 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <dirent.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
#include <sys/stat.h>
#include <limits.h>
#include <urcu.h>
#ifdef HAVE_CAP_NG_H
#include <cap-ng.h>
@ -35,6 +36,7 @@
#include "knot/ctl/process.h"
#include "knot/ctl/remote.h"
#include "knot/conf/conf.h"
#include "knot/common/log.h"
#include "knot/server/server.h"
#include "knot/server/tcp-handler.h"
#include "knot/zone/timers.h"
@ -142,7 +144,19 @@ static void event_loop(server_t *server)
/* Bind to control interface. */
uint8_t buf[KNOT_WIRE_MAX_PKTSIZE];
size_t buflen = sizeof(buf);
int remote = remote_bind(conf()->ctl.iface);
conf_val_t listen_val = conf_get(conf(), C_CTL, C_LISTEN);
conf_val_t rundir_val = conf_get(conf(), C_SRV, C_RUNDIR);
char *rundir = conf_abs_path(&rundir_val, NULL);
struct sockaddr_storage addr = conf_addr(&listen_val, rundir);
free(rundir);
int remote = remote_bind(&addr);
if (remote < 0) {
log_fatal("failed to bind control socket (%s)",
knot_strerror(remote));
return;
}
sigset_t empty;
sigemptyset(&empty);
@ -153,8 +167,7 @@ static void event_loop(server_t *server)
/* Events. */
if (ret > 0) {
ret = remote_process(server, conf()->ctl.iface,
remote, buf, buflen);
ret = remote_process(server, &addr, remote, buf, buflen);
if (ret == KNOT_CTL_STOP) {
break;
}
@ -173,7 +186,7 @@ static void event_loop(server_t *server)
server_stop(server);
/* Close remote control interface. */
remote_unbind(conf()->ctl.iface, remote);
remote_unbind(&addr, remote);
/* Wait for server to finish. */
server_wait(server);
@ -185,9 +198,12 @@ static void help(void)
PACKAGE_NAME);
printf("\nParameters:\n"
" -c, --config <file> Select configuration file.\n"
" (default %s)\n"
" -C, --confdb <dir> Select configuration database directory.\n"
" -d, --daemonize=[dir] Run server as a daemon.\n"
" -V, --version Print version of the server.\n"
" -h, --help Print help and usage.\n");
" -h, --help Print help and usage.\n",
CONF_DEFAULT_FILE);
}
int main(int argc, char **argv)
@ -195,24 +211,28 @@ int main(int argc, char **argv)
/* Parse command line arguments. */
int c = 0, li = 0;
int daemonize = 0;
const char *config_fn = conf_find_default();
const char *config_fn = CONF_DEFAULT_FILE;
const char *config_db = NULL;
const char *daemon_root = "/";
/* Long options. */
struct option opts[] = {
{"config", required_argument, 0, 'c'},
{"config", required_argument, 0, 'c' },
{"confdb", required_argument, 0, 'C' },
{"daemonize", optional_argument, 0, 'd'},
{"version", no_argument, 0, 'V'},
{"help", no_argument, 0, 'h'},
{0, 0, 0, 0}
};
while ((c = getopt_long(argc, argv, "c:dVh", opts, &li)) != -1) {
switch (c)
{
while ((c = getopt_long(argc, argv, "c:C:dVh", opts, &li)) != -1) {
switch (c) {
case 'c':
config_fn = optarg;
break;
case 'C':
config_db = optarg;
break;
case 'd':
daemonize = 1;
if (optarg) {
@ -266,41 +286,70 @@ int main(int argc, char **argv)
log_init();
/* Open configuration. */
int res = conf_open(config_fn);
conf_t *config = conf();
conf_t *new_conf = NULL;
if (config_db == NULL) {
int ret = conf_new(&new_conf, conf_scheme, NULL);
if (ret != KNOT_EOK) {
log_fatal("failed to initialize configuration database "
"(%s)", knot_strerror(ret));
return EXIT_FAILURE;
}
/* Import the configuration file. */
ret = conf_import(new_conf, config_fn, true);
if (ret != KNOT_EOK) {
log_fatal("failed to load configuration file '%s' (%s)",
config_fn, knot_strerror(ret));
conf_free(new_conf, false);
return EXIT_FAILURE;
}
new_conf->filename = strdup(config_fn);
} else {
/* Open configuration database. */
int ret = conf_new(&new_conf, conf_scheme, config_db);
if (ret != KNOT_EOK) {
log_fatal("failed to open configuration database '%s' "
"(%s)", config_db, knot_strerror(ret));
return EXIT_FAILURE;
}
}
/* Run post-open config operations. */
int res = conf_post_open(new_conf);
if (res != KNOT_EOK) {
log_fatal("failed to load configuration file '%s' (%s)",
config_fn, knot_strerror(res));
log_fatal("failed to use configuration (%s)", knot_strerror(res));
conf_free(new_conf, false);
return EXIT_FAILURE;
}
/* Initialize logging subsystem.
* @note We're logging since now. */
conf_log_reconfigure(config, NULL);
conf_add_hook(config, CONF_LOG, conf_log_reconfigure, NULL);
conf_update(new_conf);
/* Initialize logging subsystem. */
log_reconfigure(conf(), NULL);
/* Initialize server. */
server_t server;
res = server_init(&server, conf_bg_threads(config));
res = server_init(&server, conf_bg_threads(conf()));
if (res != KNOT_EOK) {
log_fatal("failed to initialize server (%s)", knot_strerror(res));
conf_free(conf());
conf_free(conf(), false);
log_close();
return EXIT_FAILURE;
}
/* Reconfigure server interfaces.
* @note This MUST be done before we drop privileges. */
server_reconfigure(config, &server);
conf_add_hook(config, CONF_ALL, server_reconfigure, &server);
log_info("configured %zu interfaces and %zu zones",
list_size(&config->ifaces), hattrie_weight(config->zones));
server_reconfigure(conf(), &server);
log_info("configured %zu zones", conf_id_count(conf(), C_ZONE));
/* Alter privileges. */
log_update_privileges(config->uid, config->gid);
if (proc_update_privileges(config->uid, config->gid) != KNOT_EOK) {
int uid, gid;
conf_user(conf(), &uid, &gid);
log_update_privileges(uid, gid);
if (proc_update_privileges(uid, gid) != KNOT_EOK) {
server_deinit(&server);
conf_free(conf());
conf_free(conf(), false);
log_close();
return EXIT_FAILURE;
}
@ -312,7 +361,7 @@ int main(int argc, char **argv)
pidfile = pid_check_and_create();
if (pidfile == NULL) {
server_deinit(&server);
conf_free(conf());
conf_free(conf(), false);
log_close();
return EXIT_FAILURE;
}
@ -329,10 +378,9 @@ int main(int argc, char **argv)
/* Now we're going multithreaded. */
rcu_register_thread();
/* Populate zone database and add reconfiguration hook. */
/* Populate zone database. */
log_info("loading zones");
server_update_zones(config, &server);
conf_add_hook(config, CONF_ALL, server_update_zones, &server);
server_update_zones(conf(), &server);
/* Check number of loaded zones. */
if (knot_zonedb_size(server.zone_db) == 0) {
@ -341,14 +389,15 @@ int main(int argc, char **argv)
/* Start it up. */
log_info("starting server");
res = server_start(&server, config->async_start);
conf_val_t async_val = conf_get(conf(), C_SRV, C_ASYNC_START);
res = server_start(&server, conf_bool(&async_val));
if (res != KNOT_EOK) {
log_fatal("failed to start server (%s)", knot_strerror(res));
server_deinit(&server);
rcu_unregister_thread();
pid_cleanup(pidfile);
log_close();
conf_free(conf());
conf_free(conf(), false);
return EXIT_FAILURE;
}
@ -360,14 +409,13 @@ int main(int argc, char **argv)
}
/* Start the event loop. */
config = NULL; /* @note Invalidate pointer, as it may change now. */
event_loop(&server);
/* Teardown server and configuration. */
server_deinit(&server);
/* Free configuration. */
conf_free(conf());
conf_free(conf(), false);
/* Unhook from RCU. */
rcu_unregister_thread();

View file

@ -14,6 +14,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <urcu.h>
#include "knot/nameserver/axfr.h"
#include "knot/nameserver/internet.h"
#include "knot/nameserver/process_query.h"
@ -108,7 +110,7 @@ static int axfr_query_check(struct query_data *qdata)
{
/* Check valid zone, transaction security and contents. */
NS_NEED_ZONE(qdata, KNOT_RCODE_NOTAUTH);
NS_NEED_AUTH(&qdata->zone->conf->acl.xfr_out, qdata);
NS_NEED_AUTH(qdata, qdata->zone->name, ACL_ACTION_XFER);
/* Check expiration. */
NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL);
@ -240,7 +242,7 @@ int axfr_query_process(knot_pkt_t *pkt, struct query_data *qdata)
}
/* Reserve space for TSIG. */
knot_pkt_reserve(pkt, knot_tsig_wire_maxsize(qdata->sign.tsig_key));
knot_pkt_reserve(pkt, knot_tsig_wire_maxsize(&qdata->sign.tsig_key));
/* Answer current packet (or continue). */
struct axfr_proc *axfr = (struct axfr_proc *)qdata->ext;

View file

@ -19,6 +19,7 @@
#include "knot/nameserver/chaos.h"
#include "knot/conf/conf.h"
#include "libknot/descriptor.h"
#include "libknot/errcode.h"
#include "libknot/packet/pkt.h"
/*!
@ -29,14 +30,24 @@ static const char *get_txt_response_string(const knot_dname_t *qname)
char *qname_str = knot_dname_to_str_alloc(qname);
const char *response = NULL;
/* id.server and hostname.bind should have similar meaning */
/* id.server and hostname.bind should have similar meaning. */
if (strcasecmp("id.server.", qname_str) == 0 ||
strcasecmp("hostname.bind.", qname_str) == 0) {
response = conf()->identity;
/* allow both version version.{server, bind}. for compatibility */
conf_val_t val = conf_get(conf(), C_SRV, C_IDENT);
response = conf_str(&val);
/* Empty string data (including '\0') means auto. */
if (val.code == KNOT_EOK && val.len <= 1) {
response = conf()->hostname;
}
/* Allow both version version.{server, bind}. for compatibility. */
} else if (strcasecmp("version.server.", qname_str) == 0 ||
strcasecmp("version.bind.", qname_str) == 0) {
response = conf()->version;
conf_val_t val = conf_get(conf(), C_SRV, C_VERSION);
response = conf_str(&val);
/* Empty string data (including '\0') means auto. */
if (val.code == KNOT_EOK && val.len <= 1) {
response = "Knot DNS " PACKAGE_VERSION;
}
}
free(qname_str);
@ -57,7 +68,7 @@ static const char *get_txt_response_string(const knot_dname_t *qname)
static int create_txt_rrset(knot_rrset_t *rrset, const knot_dname_t *owner,
const char *response, mm_ctx_t *mm)
{
// truncate response to one TXT label
/* Truncate response to one TXT label. */
size_t response_len = strlen(response);
if (response_len > KNOT_DNAME_MAXLEN) {
response_len = KNOT_DNAME_MAXLEN;

View file

@ -24,6 +24,7 @@
#include "knot/nameserver/nsec_proofs.h"
#include "knot/nameserver/process_query.h"
#include "knot/nameserver/process_answer.h"
#include "knot/nameserver/query_module.h"
#include "knot/zone/serial.h"
#include "knot/zone/zonedb.h"
@ -187,9 +188,11 @@ static int put_answer(knot_pkt_t *pkt, uint16_t type, struct query_data *qdata)
int ret = KNOT_EOK;
switch (type) {
case KNOT_RRTYPE_ANY: /* Append all RRSets. */ {
conf_val_t val = conf_zone_get(conf(), C_DISABLE_ANY,
qdata->zone->name);
/* If ANY not allowed, set TC bit. */
if ((qdata->param->proc_flags & NS_QUERY_LIMIT_ANY) &&
(qdata->zone->conf->disable_any)) {
conf_bool(&val)) {
dbg_ns("%s: ANY/UDP disabled for this zone TC=1\n", __func__);
knot_wire_set_tc(pkt->wire);
return KNOT_ESPACE;
@ -829,10 +832,10 @@ int internet_query(knot_pkt_t *response, struct query_data *qdata)
/* No applicable ACL, refuse transaction security. */
if (knot_pkt_has_tsig(qdata->query)) {
/* We have been challenged... */
NS_NEED_AUTH(&qdata->zone->conf->acl.xfr_out, qdata);
NS_NEED_AUTH(qdata, qdata->zone->name, ACL_ACTION_XFER);
/* Reserve space for TSIG. */
knot_pkt_reserve(response, knot_tsig_wire_maxsize(qdata->sign.tsig_key));
knot_pkt_reserve(response, knot_tsig_wire_maxsize(&qdata->sign.tsig_key));
}
NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL); /* Expired */
@ -841,12 +844,11 @@ int internet_query(knot_pkt_t *response, struct query_data *qdata)
qdata->name = knot_pkt_qname(qdata->query);
/* If the zone doesn't have a query plan, go for fast default. */
conf_zone_t *zone_config = qdata->zone->conf;
if (zone_config->query_plan == NULL) {
if (qdata->zone->query_plan == NULL) {
return default_answer(response, qdata);
}
return planned_answer(zone_config->query_plan, response, qdata);
return planned_answer(qdata->zone->query_plan, response, qdata);
}
int internet_query_plan(struct query_plan *plan)

View file

@ -118,8 +118,8 @@ int ns_put_rr(knot_pkt_t *pkt, const knot_rrset_t *rr,
}
/*! \brief Require authentication. */
#define NS_NEED_AUTH(acl, qdata) \
if (!process_query_acl_check((acl), (qdata))) { \
#define NS_NEED_AUTH(qdata, zone_name, action) \
if (!process_query_acl_check((zone_name), (action), (qdata))) { \
return KNOT_STATE_FAIL; \
} else { \
if (process_query_verify(qdata) != KNOT_EOK) { \

View file

@ -14,6 +14,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <urcu.h>
#include "knot/nameserver/ixfr.h"
#include "knot/nameserver/axfr.h"
#include "knot/nameserver/internet.h"
@ -164,7 +166,7 @@ static int ixfr_process_changeset(knot_pkt_t *pkt, const void *item,
#undef IXFR_SAFE_PUT
/*! \brief Loads IXFRs from journal. */
static int ixfr_load_chsets(list_t *chgsets, zone_t *zone,
static int ixfr_load_chsets(list_t *chgsets, const zone_t *zone,
const knot_rrset_t *their_soa)
{
assert(chgsets);
@ -178,9 +180,11 @@ static int ixfr_load_chsets(list_t *chgsets, zone_t *zone,
return KNOT_EUPTODATE;
}
pthread_mutex_lock(&zone->journal_lock);
ret = journal_load_changesets(zone, chgsets, serial_from, serial_to);
pthread_mutex_unlock(&zone->journal_lock);
char *path = conf_journalfile(conf(), zone->name);
pthread_mutex_lock((pthread_mutex_t *)&zone->journal_lock);
ret = journal_load_changesets(path, zone, chgsets, serial_from, serial_to);
pthread_mutex_unlock((pthread_mutex_t *)&zone->journal_lock);
free(path);
if (ret != KNOT_EOK) {
changesets_free(chgsets);
@ -208,7 +212,7 @@ static int ixfr_query_check(struct query_data *qdata)
NS_NEED_QNAME(qdata, their_soa->owner, KNOT_RCODE_FORMERR);
/* Check transcation security and zone contents. */
NS_NEED_AUTH(&qdata->zone->conf->acl.xfr_out, qdata);
NS_NEED_AUTH(qdata, qdata->zone->name, ACL_ACTION_XFER);
NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL); /* Check expiration. */
return KNOT_STATE_DONE;
@ -307,7 +311,7 @@ static int ixfr_answer_soa(knot_pkt_t *pkt, struct query_data *qdata)
}
/* Reserve space for TSIG. */
knot_pkt_reserve(pkt, knot_tsig_wire_maxsize(qdata->sign.tsig_key));
knot_pkt_reserve(pkt, knot_tsig_wire_maxsize(&qdata->sign.tsig_key));
/* Guaranteed to have zone contents. */
const zone_node_t *apex = qdata->zone->contents->apex;
@ -649,7 +653,7 @@ int ixfr_query(knot_pkt_t *pkt, struct query_data *qdata)
}
/* Reserve space for TSIG. */
knot_pkt_reserve(pkt, knot_tsig_wire_maxsize(qdata->sign.tsig_key));
knot_pkt_reserve(pkt, knot_tsig_wire_maxsize(&qdata->sign.tsig_key));
/* Answer current packet (or continue). */
ret = xfr_process_list(pkt, &ixfr_process_changeset, qdata);

View file

@ -54,7 +54,7 @@ static int notify_check_query(struct query_data *qdata)
/* Check valid zone, transaction security. */
zone_t *zone = (zone_t *)qdata->zone;
NS_NEED_ZONE(qdata, KNOT_RCODE_NOTAUTH);
NS_NEED_AUTH(&zone->conf->acl.notify_in, qdata);
NS_NEED_AUTH(qdata, zone->name, ACL_ACTION_NOTF);
return KNOT_STATE_DONE;
}
@ -80,7 +80,7 @@ int notify_process_query(knot_pkt_t *pkt, struct query_data *qdata)
}
/* Reserve space for TSIG. */
knot_pkt_reserve(pkt, knot_tsig_wire_maxsize(qdata->sign.tsig_key));
knot_pkt_reserve(pkt, knot_tsig_wire_maxsize(&qdata->sign.tsig_key));
/* SOA RR in answer may be included, recover serial. */
const knot_pktsection_t *answer = knot_pkt_section(qdata->query, KNOT_ANSWER);

View file

@ -15,6 +15,7 @@
*/
#include "libknot/libknot.h"
#include "knot/common/log.h"
#include "knot/nameserver/process_answer.h"
#include "knot/nameserver/internet.h"
#include "knot/nameserver/notify.h"

View file

@ -3,6 +3,7 @@
#include "dnssec/tsig.h"
#include "knot/nameserver/process_query.h"
#include "knot/nameserver/query_module.h"
#include "knot/nameserver/chaos.h"
#include "knot/nameserver/internet.h"
#include "knot/nameserver/axfr.h"
@ -219,7 +220,8 @@ static int answer_edns_init(const knot_pkt_t *query, knot_pkt_t *resp,
}
/* Initialize OPT record. */
int ret = knot_edns_init(&qdata->opt_rr, conf()->max_udp_payload, 0,
conf_val_t val = conf_get(conf(), C_SRV, C_MAX_UDP_PAYLOAD);
int ret = knot_edns_init(&qdata->opt_rr, conf_int(&val), 0,
KNOT_EDNS_VERSION, qdata->mm);
if (ret != KNOT_EOK) {
return ret;
@ -236,10 +238,21 @@ static int answer_edns_init(const knot_pkt_t *query, knot_pkt_t *resp,
}
/* Append NSID if requested and available. */
if (knot_edns_has_nsid(query->opt_rr) && conf()->nsid_len > 0) {
val = conf_get(conf(), C_SRV, C_NSID);
if (knot_edns_has_nsid(query->opt_rr) && val.code == KNOT_EOK) {
conf_data(&val);
const uint8_t *data = val.data;
uint16_t len = val.len;
/* Empty data means automatic value. */
if (val.len == 0) {
data = (uint8_t *)conf()->hostname;
len = strlen(conf()->hostname);
}
ret = knot_edns_add_option(&qdata->opt_rr,
KNOT_EDNS_OPTION_NSID, conf()->nsid_len,
(const uint8_t*)conf()->nsid, qdata->mm);
KNOT_EDNS_OPTION_NSID, len, data,
qdata->mm);
if (ret != KNOT_EOK) {
return ret;
}
@ -317,8 +330,9 @@ static int prepare_answer(const knot_pkt_t *query, knot_pkt_t *resp, knot_layer_
if (has_limit) {
resp->max_size = KNOT_WIRE_MIN_PKTSIZE;
if (knot_pkt_has_edns(query)) {
conf_val_t val = conf_get(conf(), C_SRV, C_MAX_UDP_PAYLOAD);
uint16_t client = knot_edns_get_payload(query->opt_rr);
uint16_t server = conf()->max_udp_payload;
uint16_t server = conf_int(&val);
uint16_t transfer = MIN(client, server);
resp->max_size = MAX(resp->max_size, transfer);
}
@ -408,7 +422,8 @@ static int ratelimit_apply(int state, knot_pkt_t *pkt, knot_layer_t *ctx)
}
/* Now it is slip or drop. */
if (rrl_slip_roll(conf()->rrl_slip)) {
conf_val_t val = conf_get(conf(), C_SRV, C_RATE_LIMIT_SLIP);
if (rrl_slip_roll(conf_int(&val))) {
/* Answer slips. */
if (process_query_err(ctx, pkt) != KNOT_EOK) {
return KNOT_STATE_FAIL;
@ -532,27 +547,27 @@ finish:
return next_state;
}
bool process_query_acl_check(list_t *acl, struct query_data *qdata)
bool process_query_acl_check(const knot_dname_t *zone_name, acl_action_t action,
struct query_data *qdata)
{
knot_pkt_t *query = qdata->query;
const struct sockaddr_storage *query_source = qdata->param->remote;
const knot_dname_t *key_name = NULL;
dnssec_tsig_algorithm_t key_alg = DNSSEC_TSIG_UNKNOWN;
knot_tsig_key_t tsig = { NULL };
/* Skip if already checked and valid. */
if (qdata->sign.tsig_key != NULL) {
if (qdata->sign.tsig_key.name != NULL) {
return true;
}
/* Authenticate with NOKEY if the packet isn't signed. */
if (query->tsig_rr) {
key_name = query->tsig_rr->owner;
key_alg = knot_tsig_rdata_alg(query->tsig_rr);
tsig.name = query->tsig_rr->owner;
tsig.algorithm = knot_tsig_rdata_alg(query->tsig_rr);
}
conf_iface_t *match = acl_find(acl, query_source, key_name);
/* Did not authenticate, no fitting rule found. */
if (match == NULL || (match->key && match->key->algorithm != key_alg)) {
/* Check if authenticated. */
conf_val_t acl = conf_zone_get(conf(), C_ACL, zone_name);
if (!acl_allowed(&acl, action, query_source, &tsig)) {
dbg_ns("%s: no ACL match => NOTAUTH\n", __func__);
qdata->rcode = KNOT_RCODE_NOTAUTH;
qdata->rcode_tsig = KNOT_TSIG_ERR_BADKEY;
@ -560,7 +575,8 @@ bool process_query_acl_check(list_t *acl, struct query_data *qdata)
}
/* Remember used TSIG key. */
qdata->sign.tsig_key = match->key;
qdata->sign.tsig_key = tsig;
return true;
}
@ -582,7 +598,7 @@ int process_query_verify(struct query_data *qdata)
/* Checking query. */
process_query_qname_case_restore(qdata, query);
int ret = knot_tsig_server_check(query->tsig_rr, query->wire,
query->size, ctx->tsig_key);
query->size, &ctx->tsig_key);
process_query_qname_case_lower(query);
dbg_ns("%s: QUERY TSIG check result = %s\n", __func__, knot_strerror(ret));
@ -628,22 +644,22 @@ int process_query_sign_response(knot_pkt_t *pkt, struct query_data *qdata)
knot_sign_context_t *ctx = &qdata->sign;
/* KEY provided and verified TSIG or BADTIME allows signing. */
if (ctx->tsig_key != NULL && knot_tsig_can_sign(qdata->rcode_tsig)) {
if (ctx->tsig_key.name != NULL && knot_tsig_can_sign(qdata->rcode_tsig)) {
/* Sign query response. */
dbg_ns("%s: signing response using key %p\n", __func__, ctx->tsig_key);
size_t new_digest_len = dnssec_tsig_algorithm_size(ctx->tsig_key->algorithm);
dbg_ns("%s: signing response using key %p\n", __func__, &ctx->tsig_key);
size_t new_digest_len = dnssec_tsig_algorithm_size(ctx->tsig_key.algorithm);
if (ctx->pkt_count == 0) {
ret = knot_tsig_sign(pkt->wire, &pkt->size, pkt->max_size,
ctx->tsig_digest, ctx->tsig_digestlen,
ctx->tsig_digest, &new_digest_len,
ctx->tsig_key, qdata->rcode_tsig,
&ctx->tsig_key, qdata->rcode_tsig,
ctx->tsig_time_signed);
} else {
ret = knot_tsig_sign_next(pkt->wire, &pkt->size, pkt->max_size,
ctx->tsig_digest, ctx->tsig_digestlen,
ctx->tsig_digest, &new_digest_len,
ctx->tsig_key,
&ctx->tsig_key,
pkt->wire, pkt->size);
}
if (ret != KNOT_EOK) {

View file

@ -113,11 +113,13 @@ struct rrsig_info {
/*!
* \brief Check current query against ACL.
*
* \param acl
* \param qdata
* \param zone_name Current zone name.
* \param action ACL action.
* \param qdata Query data.
* \return true if accepted, false if denied.
*/
bool process_query_acl_check(list_t *acl, struct query_data *qdata);
bool process_query_acl_check(const knot_dname_t *zone_name, acl_action_t action,
struct query_data *qdata);
/*!
* \brief Verify current query transaction security and update query data.

View file

@ -14,6 +14,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <urcu.h>
#include "dnssec/random.h"
#include "knot/nameserver/update.h"
#include "knot/nameserver/internet.h"
@ -78,13 +80,12 @@ static int sign_update(zone_t *zone, const zone_contents_t *old_contents,
uint32_t refresh_at = 0;
if (apex_rr_changed(old_contents, new_contents, KNOT_RRTYPE_DNSKEY) ||
apex_rr_changed(old_contents, new_contents, KNOT_RRTYPE_NSEC3PARAM)) {
ret = knot_dnssec_zone_sign(new_contents, zone->conf,
sec_ch, ZONE_SIGN_KEEP_SOA_SERIAL,
ret = knot_dnssec_zone_sign(new_contents, sec_ch,
ZONE_SIGN_KEEP_SOA_SERIAL,
&refresh_at);
} else {
// Sign the created changeset
ret = knot_dnssec_sign_changeset(new_contents, zone->conf,
ddns_ch, sec_ch,
ret = knot_dnssec_sign_changeset(new_contents, ddns_ch, sec_ch,
&refresh_at);
}
if (ret != KNOT_EOK) {
@ -237,9 +238,12 @@ static int process_normal(zone_t *zone, list_t *requests)
}
assert(new_contents);
conf_val_t val = conf_zone_get(conf(), C_DNSSEC_ENABLE, zone->name);
bool dnssec_enable = conf_bool(&val);
// Sign the update.
changeset_t sec_ch;
if (zone->conf->dnssec_enable) {
if (dnssec_enable) {
ret = changeset_init(&sec_ch, zone->name);
if (ret != KNOT_EOK) {
set_rcodes(requests, KNOT_RCODE_SERVFAIL);
@ -262,19 +266,24 @@ static int process_normal(zone_t *zone, list_t *requests)
update_rollback(&ddns_ch);
update_free_zone(&new_contents);
changeset_clear(&ddns_ch);
if (zone->conf->dnssec_enable) {
if (dnssec_enable) {
changeset_clear(&sec_ch);
}
set_rcodes(requests, KNOT_RCODE_SERVFAIL);
return ret;
}
/* Temporarily unlock locked configuration. */
rcu_read_unlock();
// Switch zone contents.
zone_contents_t *old_contents = zone_switch_contents(zone, new_contents);
synchronize_rcu();
rcu_read_lock();
// Clear DNSSEC changes
if (zone->conf->dnssec_enable) {
if (dnssec_enable) {
update_cleanup(&sec_ch);
changeset_clear(&sec_ch);
}
@ -286,7 +295,8 @@ static int process_normal(zone_t *zone, list_t *requests)
changeset_clear(&ddns_ch);
/* Sync zonefile immediately if configured. */
if (zone->conf->dbsync_timeout == 0) {
val = conf_zone_get(conf(), C_ZONEFILE_SYNC, zone->name);
if (conf_int(&val) == 0) {
zone_events_schedule(zone, ZONE_EVENT_FLUSH, ZONE_EVENT_NOW);
}
@ -331,12 +341,20 @@ static int process_requests(zone_t *zone, list_t *requests)
static int forward_request(zone_t *zone, struct knot_request *request)
{
/* Ignore if DNSSEC enabled. */
conf_val_t val = conf_zone_get(conf(), C_DNSSEC_ENABLE, zone->name);
if (conf_bool(&val)) {
log_zone_notice(zone->name, "ignoring ddns forward due to "
"enabled automatic DNSSEC signing.");
return KNOT_EOK;
}
/* Create requestor instance. */
struct knot_requestor re;
knot_requestor_init(&re, NULL);
/* Fetch primary master. */
const conf_iface_t *master = zone_master(zone);
const conf_remote_t master = zone_master(zone);
/* Copy request and assign new ID. */
knot_pkt_t *query = knot_pkt_new(NULL, request->query->max_size, NULL);
@ -350,8 +368,8 @@ static int forward_request(zone_t *zone, struct knot_request *request)
knot_tsig_append(query->wire, &query->size, query->max_size, query->tsig_rr);
/* Create a request. */
const struct sockaddr *dst = (const struct sockaddr *)&master->addr;
const struct sockaddr *src = (const struct sockaddr *)&master->via;
const struct sockaddr *dst = (const struct sockaddr *)&master.addr;
const struct sockaddr *src = (const struct sockaddr *)&master.via;
struct knot_request *req = knot_request_make(re.mm, dst, src, query, 0);
if (req == NULL) {
knot_pkt_free(&query);
@ -366,7 +384,8 @@ static int forward_request(zone_t *zone, struct knot_request *request)
/* Enqueue and execute request. */
ret = knot_requestor_enqueue(&re, req);
if (ret == KNOT_EOK) {
struct timeval tv = { conf()->max_conn_reply, 0 };
conf_val_t val = conf_get(conf(), C_SRV, C_MAX_CONN_REPLY);
struct timeval tv = { conf_int(&val), 0 };
ret = knot_requestor_exec(&re, &tv);
}
@ -400,7 +419,7 @@ static void forward_requests(zone_t *zone, list_t *requests)
static bool update_tsig_check(struct query_data *qdata, struct knot_request *req)
{
// Check that ACL is still valid.
if (!process_query_acl_check(&qdata->zone->conf->acl.update_in, qdata)) {
if (!process_query_acl_check(qdata->zone->name, ACL_ACTION_DDNS, qdata)) {
UPDATE_LOG(LOG_WARNING, "ACL check failed");
knot_wire_set_rcode(req->resp->wire, qdata->rcode);
return false;
@ -426,7 +445,7 @@ static bool update_tsig_check(struct query_data *qdata, struct knot_request *req
static void send_update_response(const zone_t *zone, struct knot_request *req)
{
if (req->resp) {
if (!zone_master(zone)) {
if (zone_is_master(zone)) {
// Sign the response with TSIG where applicable
struct query_data qdata;
init_qdata_from_request(&qdata, zone, req, NULL);
@ -475,7 +494,7 @@ static int init_update_responses(const zone_t *zone, list_t *updates,
assert(req->query);
knot_pkt_init_response(req->resp, req->query);
if (zone_master(zone)) {
if (!zone_is_master(zone)) {
// Don't check TSIG for forwards.
continue;
}
@ -507,7 +526,7 @@ int update_query_process(knot_pkt_t *pkt, struct query_data *qdata)
/* Need valid transaction security. */
zone_t *zone = (zone_t *)qdata->zone;
NS_NEED_AUTH(&zone->conf->acl.update_in, qdata);
NS_NEED_AUTH(qdata, zone->name, ACL_ACTION_DDNS);
/* Check expiration. */
NS_NEED_ZONE_CONTENTS(qdata, KNOT_RCODE_SERVFAIL);
@ -533,22 +552,27 @@ int updates_execute(zone_t *zone)
return KNOT_EOK;
}
/* Block config changes. */
rcu_read_lock();
/* Init updates respones. */
int ret = init_update_responses(zone, &updates, &update_count);
if (ret != KNOT_EOK) {
/* Send what responses we can. */
set_rcodes(&updates, KNOT_RCODE_SERVFAIL);
send_update_responses(zone, &updates);
rcu_read_unlock();
return ret;
}
if (update_count == 0) {
/* All updates failed their ACL checks. */
rcu_read_unlock();
return KNOT_EOK;
}
/* Process update list - forward if zone has master, or execute. */
if (zone_master(zone)) {
if (!zone_is_master(zone)) {
log_zone_info(zone->name,
"DDNS, forwarding %zu updates", update_count);
forward_requests(zone, &updates);
@ -562,5 +586,6 @@ int updates_execute(zone_t *zone)
/* Send responses. */
send_update_responses(zone, &updates);
rcu_read_unlock();
return KNOT_EOK;
}

View file

@ -998,9 +998,10 @@ static int load_changeset(journal_t *journal, journal_node_t *n, const zone_t *z
return KNOT_EOK;
}
int journal_load_changesets(const zone_t *zone, list_t *dst, uint32_t from, uint32_t to)
int journal_load_changesets(const char *path, const zone_t *zone, list_t *dst,
uint32_t from, uint32_t to)
{
int ret = journal_walk(zone->conf->ixfr_db, from, to, &load_changeset, zone, dst);
int ret = journal_walk(path, from, to, &load_changeset, zone, dst);
if (ret != KNOT_EOK) {
return ret;
}

View file

@ -169,6 +169,7 @@ bool journal_exists(const char *path);
* \brief Load changesets from journal.
*
* \param path Path to journal file.
* \param zone Corresponding zone.
* \param dst Store changesets here.
* \param from Start serial.
* \param to End serial.
@ -177,7 +178,7 @@ bool journal_exists(const char *path);
* \retval KNOT_ERANGE if given entry was not found.
* \return < KNOT_EOK on error.
*/
int journal_load_changesets(const struct zone *zone, list_t *dst,
int journal_load_changesets(const char *path, const struct zone *zone, list_t *dst,
uint32_t from, uint32_t to);
/*!

View file

@ -14,6 +14,8 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <urcu.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
@ -93,23 +95,23 @@ static void server_remove_iface(iface_t *iface)
* \retval 0 if successful (EOK).
* \retval <0 on errors (EACCES, EINVAL, ENOMEM, EADDRINUSE).
*/
static int server_init_iface(iface_t *new_if, conf_iface_t *cfg_if)
static int server_init_iface(iface_t *new_if, struct sockaddr_storage *addr)
{
/* Initialize interface. */
int ret = 0;
memset(new_if, 0, sizeof(iface_t));
memcpy(&new_if->addr, &cfg_if->addr, sizeof(struct sockaddr_storage));
memcpy(&new_if->addr, addr, sizeof(struct sockaddr_storage));
/* Convert to string address format. */
char addr_str[SOCKADDR_STRLEN] = {0};
sockaddr_tostr(addr_str, sizeof(addr_str), &cfg_if->addr);
char addr_str[SOCKADDR_STRLEN] = { 0 };
sockaddr_tostr(addr_str, sizeof(addr_str), addr);
/* Create bound UDP socket. */
int bind_flags = 0;
int sock = net_bound_socket(SOCK_DGRAM, &cfg_if->addr, bind_flags);
int sock = net_bound_socket(SOCK_DGRAM, addr, bind_flags);
if (sock == KNOT_EADDRNOTAVAIL) {
bind_flags |= NET_BIND_NONLOCAL;
sock = net_bound_socket(SOCK_DGRAM, &cfg_if->addr, bind_flags);
sock = net_bound_socket(SOCK_DGRAM, addr, bind_flags);
if (sock >= 0) {
log_warning("address '%s' is not available", addr_str);
}
@ -126,7 +128,7 @@ static int server_init_iface(iface_t *new_if, conf_iface_t *cfg_if)
new_if->fd[IO_UDP] = sock;
/* Create bound TCP socket. */
sock = net_bound_socket(SOCK_STREAM, &cfg_if->addr, bind_flags);
sock = net_bound_socket(SOCK_STREAM, addr, bind_flags);
if (sock < 0) {
close(new_if->fd[IO_UDP]);
return sock;
@ -180,12 +182,10 @@ static void remove_ifacelist(struct ref *p)
* \param server Server instance.
* \return number of added sockets.
*/
static int reconfigure_sockets(const struct conf *conf, server_t *s)
static int reconfigure_sockets(conf_t *conf, server_t *s)
{
/* Prepare helper lists. */
char addr_str[SOCKADDR_STRLEN] = {0};
int bound = 0;
iface_t *m = 0;
ifacelist_t *oldlist = s->ifaces;
ifacelist_t *newlist = malloc(sizeof(ifacelist_t));
ref_init(&newlist->ref, &remove_ifacelist);
@ -200,16 +200,19 @@ static int reconfigure_sockets(const struct conf *conf, server_t *s)
}
/* Update bound interfaces. */
node_t *n = 0;
WALK_LIST(n, conf->ifaces) {
conf_val_t listen_val = conf_get(conf, C_SRV, C_LISTEN);
conf_val_t rundir_val = conf_get(conf, C_SRV, C_RUNDIR);
char *rundir = conf_abs_path(&rundir_val, NULL);
while (listen_val.code == KNOT_EOK) {
iface_t *m = NULL;
/* Find already matching interface. */
int found_match = 0;
conf_iface_t *cfg_if = (conf_iface_t*)n;
struct sockaddr_storage addr = conf_addr(&listen_val, rundir);
if (s->ifaces) {
WALK_LIST(m, s->ifaces->u) {
/* Matching port and address. */
if (sockaddr_cmp(&cfg_if->addr, &m->addr) == 0) {
if (sockaddr_cmp(&addr, &m->addr) == 0) {
found_match = 1;
break;
}
@ -220,12 +223,13 @@ static int reconfigure_sockets(const struct conf *conf, server_t *s)
if (found_match) {
rem_node((node_t *)m);
} else {
sockaddr_tostr(addr_str, sizeof(addr_str), &cfg_if->addr);
char addr_str[SOCKADDR_STRLEN] = { 0 };
sockaddr_tostr(addr_str, sizeof(addr_str), &addr);
log_info("binding to interface '%s'", addr_str);
/* Create new interface. */
m = malloc(sizeof(iface_t));
if (server_init_iface(m, cfg_if) < 0) {
if (server_init_iface(m, &addr) < 0) {
free(m);
m = 0;
}
@ -236,7 +240,10 @@ static int reconfigure_sockets(const struct conf *conf, server_t *s)
add_tail(&newlist->l, (node_t *)m);
++bound;
}
conf_val_next(&listen_val);
}
free(rundir);
/* Wait for readers that are reconfiguring right now. */
/*! \note This subsystem will be reworked in #239 */
@ -436,27 +443,52 @@ void server_wait(server_t *s)
int server_reload(server_t *server, const char *cf)
{
if (!server || !cf) {
if (server == NULL) {
return KNOT_EINVAL;
}
log_info("reloading configuration");
int cf_ret = conf_open(cf);
switch (cf_ret) {
case KNOT_EOK:
log_info("configuration reloaded");
break;
case KNOT_ENOENT:
log_error("configuration file '%s' not found",
conf()->filename);
break;
default:
log_error("failed to reload the configuration");
break;
int ret = KNOT_EOK;
if (cf != NULL) {
log_info("reloading configuration file '%s'", cf);
conf_t *new_conf = NULL;
ret = conf_clone(&new_conf);
if (ret != KNOT_EOK) {
log_fatal("failed to initialize configuration (%s)",
knot_strerror(ret));
return EXIT_FAILURE;
}
/* Import the configuration file. */
ret = conf_import(new_conf, cf, true);
if (ret != KNOT_EOK) {
log_fatal("failed to load configuration file '%s' (%s)",
cf, knot_strerror(ret));
conf_free(new_conf, false);
return EXIT_FAILURE;
}
/* Run post-open config operations. */
int res = conf_post_open(new_conf);
if (res != KNOT_EOK) {
log_fatal("failed to use configuration (%s)",
knot_strerror(res));
conf_free(new_conf, false);
return EXIT_FAILURE;
}
conf_update(new_conf);
} else {
log_info("reloading configuration database");
}
/*! \todo Close and bind to new remote control. */
return cf_ret;
log_reconfigure(conf(), NULL);
server_reconfigure(conf(), server);
server_update_zones(conf(), server);
log_info("configuration reloaded");
return ret;
}
void server_stop(server_t *server)
@ -476,7 +508,7 @@ void server_stop(server_t *server)
}
/*! \brief Reconfigure UDP and TCP query processing threads. */
static int reconfigure_threads(const struct conf *conf, server_t *server)
static int reconfigure_threads(conf_t *conf, server_t *server)
{
/* Estimate number of threads/manager. */
int ret = KNOT_EOK;
@ -520,11 +552,15 @@ static int reconfigure_threads(const struct conf *conf, server_t *server)
return ret;
}
static int reconfigure_rate_limits(const struct conf *conf, server_t *server)
static int reconfigure_rate_limits(conf_t *conf, server_t *server)
{
conf_val_t val = conf_get(conf, C_SRV, C_RATE_LIMIT);
int64_t rrl = conf_int(&val);
/* Rate limiting. */
if (!server->rrl && conf->rrl > 0) {
server->rrl = rrl_create(conf->rrl_size);
if (!server->rrl && rrl > 0) {
val = conf_get(conf, C_SRV, C_RATE_LIMIT_SIZE);
server->rrl = rrl_create(conf_int(&val));
if (!server->rrl) {
log_error("failed to initialize rate limiting table");
} else {
@ -532,16 +568,16 @@ static int reconfigure_rate_limits(const struct conf *conf, server_t *server)
}
}
if (server->rrl) {
if (rrl_rate(server->rrl) != (uint32_t)conf->rrl) {
if (rrl_rate(server->rrl) != rrl) {
/* We cannot free it, threads may use it.
* Setting it to <1 will disable rate limiting. */
if (conf->rrl < 1) {
if (rrl < 1) {
log_info("rate limiting, disabled");
} else {
log_info("rate limiting, enabled with %u responses/second",
conf->rrl);
log_info("rate limiting, enabled with %i responses/second",
(int)rrl);
}
rrl_setrate(server->rrl, conf->rrl);
rrl_setrate(server->rrl, rrl);
} /* At this point, old buckets will converge to new rate. */
}
@ -549,7 +585,7 @@ static int reconfigure_rate_limits(const struct conf *conf, server_t *server)
return KNOT_EOK;
}
int server_reconfigure(const struct conf *conf, void *data)
int server_reconfigure(conf_t *conf, void *data)
{
server_t *server = (server_t *)data;
dbg_server("%s(%p, %p)\n", __func__, conf, server);
@ -584,19 +620,22 @@ int server_reconfigure(const struct conf *conf, void *data)
return ret;
}
static void reopen_timers_database(const conf_t *conf, server_t *server)
static void reopen_timers_database(conf_t *conf, server_t *server)
{
close_timers_db(server->timers_db);
server->timers_db = NULL;
int ret = open_timers_db(conf->storage, &server->timers_db);
conf_val_t val = conf_default_get(conf, C_STORAGE);
char *storage = conf_abs_path(&val, NULL);
int ret = open_timers_db(storage, &server->timers_db);
free(storage);
if (ret != KNOT_EOK && ret != KNOT_ENOTSUP) {
log_warning("cannot open persistent timers DB (%s)",
knot_strerror(ret));
}
}
int server_update_zones(const conf_t *conf, void *data)
int server_update_zones(conf_t *conf, void *data)
{
server_t *server = (server_t *)data;

View file

@ -178,7 +178,7 @@ void server_stop(server_t *server);
* \retval KNOT_EINVAL on invalid parameters.
* \retval KNOT_ERROR unspecified error.
*/
int server_reconfigure(const struct conf *conf, void *data);
int server_reconfigure(conf_t *conf, void *data);
/*!
* \brief Reconfigure zone database.
@ -187,7 +187,7 @@ int server_reconfigure(const struct conf *conf, void *data);
*
* \return KNOT_EOK on success or KNOT_ error
*/
int server_update_zones(const struct conf *conf, void *data);
int server_update_zones(conf_t *conf, void *data);
/*!
* \brief Update fdsets from current interfaces list.

View file

@ -24,6 +24,7 @@
#include <netinet/in.h>
#include <stdio.h>
#include <stdlib.h>
#include <urcu.h>
#ifdef HAVE_SYS_UIO_H // struct iovec (OpenBSD)
#include <sys/uio.h>
#endif // HAVE_SYS_UIO_H
@ -112,20 +113,20 @@ static int tcp_handle(tcp_context_t *tcp, int fd,
/* Timeout. */
rcu_read_lock();
struct timeval tmout = { conf()->max_conn_reply, 0 };
conf_val_t val = conf_get(conf(), C_SRV, C_MAX_CONN_REPLY);
int64_t max_conn_reply = conf_int(&val);
rcu_read_unlock();
struct timeval tmout = { max_conn_reply, 0 };
/* Receive data. */
int ret = tcp_recv_msg(fd, rx->iov_base, rx->iov_len, &tmout);
if (ret <= 0) {
dbg_net("tcp: client on fd=%d disconnected\n", fd);
if (ret == KNOT_EAGAIN) {
rcu_read_lock();
char addr_str[SOCKADDR_STRLEN] = {0};
sockaddr_tostr(addr_str, sizeof(addr_str), &ss);
log_warning("TCP, connection timed out, address '%s'",
addr_str);
rcu_read_unlock();
}
return KNOT_ECONNREFUSED;
} else {
@ -187,7 +188,8 @@ int tcp_accept(int fd)
#ifdef SO_RCVTIMEO
struct timeval tv;
rcu_read_lock();
tv.tv_sec = conf()->max_conn_idle;
conf_val_t val = conf_get(conf(), C_SRV, C_MAX_CONN_IDLE);
tv.tv_sec = conf_int(&val);
rcu_read_unlock();
tv.tv_usec = 0;
if (setsockopt(incoming, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
@ -215,7 +217,8 @@ static int tcp_event_accept(tcp_context_t *tcp, unsigned i)
/* Update watchdog timer. */
rcu_read_lock();
fdset_set_watchdog(&tcp->set, next_id, conf()->max_conn_hs);
conf_val_t val = conf_get(conf(), C_SRV, C_MAX_CONN_HANDSHAKE);
fdset_set_watchdog(&tcp->set, next_id, conf_int(&val));
rcu_read_unlock();
return KNOT_EOK;
@ -235,7 +238,8 @@ static int tcp_event_serve(tcp_context_t *tcp, unsigned i)
if (ret == KNOT_EOK) {
/* Update socket activity timer. */
rcu_read_lock();
fdset_set_watchdog(&tcp->set, i, conf()->max_conn_idle);
conf_val_t val = conf_get(conf(), C_SRV, C_MAX_CONN_IDLE);
fdset_set_watchdog(&tcp->set, i, conf_int(&val));
rcu_read_unlock();
}
@ -254,7 +258,8 @@ static int tcp_wait_for_events(tcp_context_t *tcp)
if (!is_throttled) {
/* Configuration limit, infer maximal pool size. */
rcu_read_lock();
unsigned max_per_set = MAX(conf()->max_tcp_clients / conf_tcp_threads(conf()), 1);
conf_val_t val = conf_get(conf(), C_SRV, C_MAX_TCP_CLIENTS);
unsigned max_per_set = MAX(conf_int(&val) / conf_tcp_threads(conf()), 1);
rcu_read_unlock();
/* Subtract master sockets check limits. */
is_throttled = (set->n - tcp->client_threshold) >= max_per_set;
@ -320,7 +325,8 @@ int tcp_master(dthread_t *thread)
tcp.overlay.mm = &mm;
/* Prepare structures for bound sockets. */
fdset_init(&tcp.set, list_size(&conf()->ifaces) + CONFIG_XFERS);
conf_val_t val = conf_get(conf(), C_SRV, C_LISTEN);
fdset_init(&tcp.set, conf_val_count(&val) + CONF_XFERS);
/* Create iovec abstraction. */
for (unsigned i = 0; i < 2; ++i) {

View file

@ -29,6 +29,7 @@
#include <errno.h>
#include <limits.h>
#include <sys/param.h>
#include <urcu.h>
#ifdef HAVE_SYS_UIO_H /* 'struct iovec' for OpenBSD */
#include <sys/uio.h>
#endif /* HAVE_SYS_UIO_H */

View file

@ -22,135 +22,155 @@
#include <limits.h>
#include <stdbool.h>
#include "libknot/libknot.h"
#include "knot/updates/acl.h"
#include "knot/conf/conf.h"
#include "libknot/libknot.h"
#include "libknot/internal/endian.h"
#include "libknot/rrtype/tsig.h"
#include "libknot/internal/sockaddr.h"
static inline uint32_t ipv4_chunk(const struct sockaddr_in *ipv4)
{
/* Stored as big end first. */
return ipv4->sin_addr.s_addr;
static const uint8_t* ipv4_addr(const struct sockaddr_storage *ss) {
struct sockaddr_in *ipv4 = (struct sockaddr_in *)ss;
return (uint8_t *)&ipv4->sin_addr.s_addr;
}
static inline uint32_t ipv6_chunk(const struct sockaddr_in6 *ipv6, uint8_t idx)
{
/* Is byte array, 4x 32bit value. */
return ((uint32_t *)&ipv6->sin6_addr)[idx];
static const uint8_t* ipv6_addr(const struct sockaddr_storage *ss) {
struct sockaddr_in6 *ipv6 = (struct sockaddr_in6 *)ss;
return (uint8_t *)&ipv6->sin6_addr.s6_addr;
}
static inline uint32_t ip_chunk(const struct sockaddr_storage *ss, uint8_t idx)
bool netblock_match(const struct sockaddr_storage *ss1,
const struct sockaddr_storage *ss2,
unsigned prefix)
{
if (ss->ss_family == AF_INET6) {
return ipv6_chunk((const struct sockaddr_in6 *)ss, idx);
} else {
return ipv4_chunk((const struct sockaddr_in *)ss);
}
}
/*! \brief Compare chunks using given mask. */
static int cmp_chunk(const conf_iface_t *a1, const struct sockaddr_storage *a2,
uint8_t idx, uint32_t mask)
{
const uint32_t c1 = ip_chunk(&a1->addr, idx) & mask;
const uint32_t c2 = ip_chunk(a2, idx) & mask;
if (c1 > c2)
return 1;
if (c1 < c2)
return -1;
return 0;
}
/*!
* \brief Calculate bitmask for byte array from the MSB.
*
* \note i.e. 8 means top 8 bits set, 11111111000000000000000000000000
*
* \param nbits number of bits set to 1
* \return mask
*/
static uint32_t acl_fill_mask32(short nbits)
{
assert(nbits >= 0 && nbits <= 32);
uint32_t r = 0;
for (char i = 0; i < nbits; ++i) {
r |= 1 << (31 - i);
if (ss1 == NULL || ss2 == NULL) {
return false;
}
/* Make sure the mask is in network byte order. */
return htonl(r);
}
if (ss1->ss_family != ss2->ss_family) {
return false;
}
int netblock_match(struct conf_iface *a1, const struct sockaddr_storage *a2)
{
int ret = 0;
uint32_t mask = 0xffffffff;
short mask_bits = a1->prefix;
const short chunk_bits = sizeof(mask) * CHAR_BIT;
const uint8_t *addr1, *addr2;
switch (ss1->ss_family) {
case AF_INET:
addr1 = ipv4_addr(ss1);
addr2 = ipv4_addr(ss2);
prefix = prefix > IPV4_PREFIXLEN ? IPV4_PREFIXLEN : prefix;
break;
case AF_INET6:
addr1 = ipv6_addr(ss1);
addr2 = ipv6_addr(ss2);
prefix = prefix > IPV6_PREFIXLEN ? IPV6_PREFIXLEN : prefix;
break;
default:
return false;
}
/* Check different length, IPv4 goes first. */
if (a1->addr.ss_family != a2->ss_family) {
if (a1->addr.ss_family < a2->ss_family) {
return -1;
} else {
return 1;
/* Compare full bytes address block. */
uint8_t full_bytes = prefix / 8;
for (int i = 0; i < full_bytes; i++) {
if (addr1[i] != addr2[i]) {
return false;
}
}
/* At most 4xchunk_bits for IPv6 */
unsigned i = 0;
while (ret == 0 && mask_bits > 0) {
/* Compute mask for current chunk. */
if (mask_bits <= chunk_bits) {
mask = acl_fill_mask32(mask_bits);
mask_bits = 0; /* Last chunk */
} else {
mask_bits -= chunk_bits;
/* Compare last partial byte address block. */
uint8_t rest_bits = prefix % 8;
if (rest_bits > 0) {
uint8_t rest1 = addr1[full_bytes] >> (8 - rest_bits);
uint8_t rest2 = addr2[full_bytes] >> (8 - rest_bits);
if (rest1 != rest2) {
return false;
}
/* Empty mask - shortcut, we're done. */
if (mask > 0) {
ret = cmp_chunk(a1, a2, i, mask);
}
++i;
}
return ret;
return true;
}
struct conf_iface* acl_find(list_t *acl, const struct sockaddr_storage *addr,
const knot_dname_t *key_name)
bool acl_allowed(conf_val_t *acl, acl_action_t action,
const struct sockaddr_storage *addr,
knot_tsig_key_t *tsig)
{
if (acl == NULL || addr == NULL) {
if (acl == NULL || addr == NULL || tsig == NULL) {
return NULL;
}
conf_remote_t *remote = NULL;
WALK_LIST(remote, *acl) {
conf_iface_t *cur = remote->remote;
if (netblock_match(cur, addr) == 0) {
/* NOKEY entry. */
if (cur->key == NULL) {
if (key_name == NULL) {
return cur;
}
/* NOKEY entry, but key provided. */
continue;
while (acl->code == KNOT_EOK) {
/* Check if the action is allowed. */
bool match = false, deny = false;
conf_val_t action_val = conf_id_get(conf(), C_ACL, C_ACTION, acl);
while (action_val.code == KNOT_EOK) {
unsigned act = conf_opt(&action_val);
if (act & action) {
match = true;
}
/* NOKEY provided, but key required. */
if (key_name == NULL) {
continue;
if (act == ACL_ACTION_DENY) {
deny = true;
}
conf_val_next(&action_val);
}
if (!match) {
conf_val_next(acl);
continue;
}
/* Key name match. */
if (knot_dname_is_equal(cur->key->name, key_name)) {
return cur;
/* Check if the address prefix matches. */
conf_val_t addr_val = conf_id_get(conf(), C_ACL, C_ADDR, acl);
if (addr_val.code == KNOT_EOK) {
unsigned prefix;
struct sockaddr_storage ss;
ss = conf_net(&addr_val, &prefix);
if (!netblock_match(addr, &ss, prefix)) {
conf_val_next(acl);
continue;
}
}
/* Check if the key matches. */
conf_val_t key_val = conf_id_get(conf(), C_ACL, C_KEY, acl);
if (key_val.code == KNOT_EOK) {
/* No key provided, but required. */
if (tsig->name == NULL) {
conf_val_next(acl);
continue;
}
/* Compare key names. */
const knot_dname_t *key_name = conf_dname(&key_val);
if (knot_dname_cmp(key_name, tsig->name) != 0) {
conf_val_next(acl);
continue;
}
/* Compare key algorithms. */
conf_val_t alg_val = conf_id_get(conf(), C_KEY, C_ALG,
&key_val);
if (conf_opt(&alg_val) != tsig->algorithm) {
conf_val_next(acl);
continue;
}
/* No key required, but provided. */
} else if (tsig->name != NULL) {
conf_val_next(acl);
continue;
}
if (deny) {
conf_val_next(acl);
continue;
}
/* Fill the output with tsig secret. */
if (tsig->name != NULL) {
conf_val_t secret_val = conf_id_get(conf(), C_KEY,
C_SECRET, &key_val);
conf_data(&secret_val);
tsig->secret.data = (uint8_t *)secret_val.data;
tsig->secret.size = secret_val.len;
}
return true;
}
return NULL;
return false;
}

View file

@ -14,16 +14,11 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*!
* \file acl.h
* \file
*
* \author Marek Vavrusa <marek.vavrusa@nic.cz>
* Access control list.
*
* \brief Access control lists.
*
* Simple access control list is implemented as a linked list, sorted by
* prefix length. This way, longest prefix match is always found first.
*
* \addtogroup common_lib
* \addtogroup server
* @{
*/
@ -33,23 +28,44 @@
#include "libknot/internal/sockaddr.h"
#include "libknot/internal/mempattern.h"
#include "libknot/rrtype/tsig.h"
#include "knot/conf/conf.h"
struct conf_iface;
/*! \brief Match address against netblock. */
int netblock_match(struct conf_iface *a1, const struct sockaddr_storage *a2);
/*! \brief ACL actions. */
typedef enum {
ACL_ACTION_DENY = 0,
ACL_ACTION_XFER = 1,
ACL_ACTION_NOTF = 2,
ACL_ACTION_DDNS = 3,
ACL_ACTION_CNTL = 4
} acl_action_t;
/*!
* \brief Match address against ACL.
* \brief Checks if two netblocks match.
*
* \param acl Pointer to ACL instance.
* \param addr IP address.
* \param key_name TSIG key name (optional)
*
* \retval Matching rule instance if found.
* \retval NULL if it didn't find a match.
* \param ss1 First address storage.
* \param ss2 Second address storage.
* \param prefix Netblock length.
*/
struct conf_iface* acl_find(list_t *acl, const struct sockaddr_storage *addr,
const knot_dname_t *key_name);
bool netblock_match(const struct sockaddr_storage *ss1,
const struct sockaddr_storage *ss2,
unsigned prefix);
/*!
* \brief Checks if the address and/or tsig key matches given ACL list.
*
* If a proper ACL rule is found and tsig.name is not empty,
* tsig.secret is filled.
*
* \param acl Pointer to ACL config multivalued identifier.
* \param action ACL action.
* \param addr IP address.
* \param tsig TSIG parameters.
*
* \retval true if authenticated.
* \retval false if not authenticated.
*/
bool acl_allowed(conf_val_t *acl, acl_action_t action,
const struct sockaddr_storage *addr,
knot_tsig_key_t *tsig);
/*! @} */

View file

@ -15,6 +15,7 @@
*/
#include <assert.h>
#include <urcu.h>
#include "knot/updates/apply.h"
@ -453,10 +454,13 @@ int apply_changesets(zone_t *zone, list_t *chsets, zone_contents_t **new_content
/*
* Apply the changesets.
*/
rcu_read_lock();
bool is_master = zone_is_master(zone);
rcu_read_unlock();
changeset_t *set = NULL;
const bool master = (zone_master(zone) == NULL);
WALK_LIST(set, *chsets) {
ret = apply_single(contents_copy, set, master);
ret = apply_single(contents_copy, set, is_master);
if (ret != KNOT_EOK) {
updates_rollback(chsets);
update_free_zone(&contents_copy);
@ -495,8 +499,11 @@ int apply_changeset(zone_t *zone, changeset_t *change, zone_contents_t **new_con
return ret;
}
const bool master = (zone_master(zone) == NULL);
ret = apply_single(contents_copy, change, master);
rcu_read_lock();
bool is_master = zone_is_master(zone);
rcu_read_unlock();
ret = apply_single(contents_copy, change, is_master);
if (ret != KNOT_EOK) {
update_rollback(change);
update_free_zone(&contents_copy);

View file

@ -17,7 +17,9 @@
#include <assert.h>
#include <stdlib.h>
#include <inttypes.h>
#include <urcu.h>
#include "knot/common/log.h"
#include "knot/updates/ddns.h"
#include "knot/updates/changesets.h"
#include "knot/updates/zone-update.h"
@ -971,8 +973,9 @@ int ddns_process_update(const zone_t *zone, const knot_pkt_t *query,
return KNOT_ENOMEM;
}
conf_val_t val = conf_zone_get(conf(), C_SERIAL_POLICY, zone->name);
uint32_t old_serial = knot_soa_serial(&soa_cpy->rrs);
uint32_t new_serial = serial_next(old_serial, zone->conf->serial_policy);
uint32_t new_serial = serial_next(old_serial, conf_opt(&val));
if (serial_compare(old_serial, new_serial) >= 0) {
log_zone_warning(zone->name, "updated serial is lower "
"than current, serial %u -> %u",

View file

@ -18,6 +18,7 @@
#include <time.h>
#include "knot/common/evsched.h"
#include "knot/common/log.h"
#include "libknot/libknot.h"
#include "libknot/internal/namedb/namedb.h"
#include "knot/server/server.h"

View file

@ -14,15 +14,16 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <urcu.h>
#include "dnssec/random.h"
#include "libknot/libknot.h"
#include "libknot/processing/requestor.h"
#include "libknot/rrtype/soa.h"
#include "knot/common/trim.h"
#include "libknot/internal/mempool.h"
#include "libknot/internal/macros.h"
#include "libknot/processing/requestor.h"
#include "knot/common/log.h"
#include "knot/common/trim.h"
#include "knot/server/udp-handler.h"
#include "knot/server/tcp-handler.h"
#include "knot/updates/changesets.h"
@ -46,7 +47,7 @@
/*! \brief Zone event logging. */
#define ZONE_QUERY_LOG(severity, zone, remote, operation, msg...) \
NS_PROC_LOG(severity, &remote->addr, zone->name, operation, msg)
NS_PROC_LOG(severity, &(remote)->addr, zone->name, operation, msg)
/*! \brief Create zone query packet. */
static knot_pkt_t *zone_query(const zone_t *zone, uint16_t pkt_type, mm_ctx_t *mm)
@ -91,7 +92,7 @@ static knot_pkt_t *zone_query(const zone_t *zone, uint16_t pkt_type, mm_ctx_t *m
* \note Everything in this function is executed synchronously, returns when
* the query processing is either complete or an error occurs.
*/
static int zone_query_execute(zone_t *zone, uint16_t pkt_type, const conf_iface_t *remote)
static int zone_query_execute(zone_t *zone, uint16_t pkt_type, const conf_remote_t *remote)
{
/* Create a memory pool for this task. */
int ret = KNOT_EOK;
@ -115,7 +116,9 @@ static int zone_query_execute(zone_t *zone, uint16_t pkt_type, const conf_iface_
knot_requestor_init(&re, &mm);
knot_requestor_overlay(&re, KNOT_STATE_ANSWER, &param);
tsig_init(&param.tsig_ctx, remote->key);
const knot_tsig_key_t *key = remote->key.name != NULL ?
&remote->key : NULL;
tsig_init(&param.tsig_ctx, key);
ret = tsig_sign_packet(&param.tsig_ctx, query);
if (ret != KNOT_EOK) {
@ -134,7 +137,8 @@ static int zone_query_execute(zone_t *zone, uint16_t pkt_type, const conf_iface_
/* Send the queries and process responses. */
ret = knot_requestor_enqueue(&re, req);
if (ret == KNOT_EOK) {
struct timeval tv = { conf()->max_conn_reply, 0 };
conf_val_t val = conf_get(conf(), C_SRV, C_MAX_CONN_REPLY);
struct timeval tv = { conf_int(&val), 0 };
ret = knot_requestor_exec(&re, &tv);
}
@ -156,7 +160,7 @@ fail:
}
/*! \brief Execute zone transfer request. */
static int zone_query_transfer(zone_t *zone, const conf_iface_t *master, uint16_t pkt_type)
static int zone_query_transfer(zone_t *zone, const conf_remote_t *master, uint16_t pkt_type)
{
assert(zone);
assert(master);
@ -215,7 +219,8 @@ static uint32_t soa_graceful_expire(const knot_rdataset_t *soa)
{
// Allow for timeouts. Otherwise zones with very short
// expiry may expire before the timeout is reached.
return knot_soa_expire(soa) + 2 * conf()->max_conn_idle;
conf_val_t val = conf_get(conf(), C_SRV, C_MAX_CONN_IDLE);
return knot_soa_expire(soa) + 2 * conf_int(&val);
}
/*! \brief Schedule expire event, unless it is already scheduled. */
@ -235,24 +240,25 @@ int event_reload(zone_t *zone)
assert(zone);
/* Take zone file mtime and load it. */
time_t mtime = zonefile_mtime(zone->conf->file);
char *filename = conf_zonefile(conf(), zone->name);
time_t mtime = zonefile_mtime(filename);
free(filename);
uint32_t dnssec_refresh = time(NULL);
conf_zone_t *zone_config = zone->conf;
zone_contents_t *contents = zone_load_contents(zone_config);
zone_contents_t *contents = zone_load_contents(conf(), zone->name);
if (!contents) {
return KNOT_ERROR;
}
/* Store zonefile serial and apply changes from the journal. */
zone->zonefile_serial = zone_contents_serial(contents);
int result = zone_load_journal(zone, contents);
int result = zone_load_journal(conf(), zone, contents);
if (result != KNOT_EOK) {
goto fail;
}
/* Post load actions - calculate delta, sign with DNSSEC... */
/*! \todo issue #242 dnssec signing should occur in the special event */
result = zone_load_post(contents, zone, &dnssec_refresh);
result = zone_load_post(conf(), contents, zone, &dnssec_refresh);
if (result != KNOT_EOK) {
if (result == KNOT_ESPACE) {
log_zone_error(zone->name, "journal size is too small "
@ -265,7 +271,7 @@ int event_reload(zone_t *zone)
}
/* Check zone contents consistency. */
result = zone_load_check(contents, zone_config);
result = zone_load_check(conf(), contents);
if (result != KNOT_EOK) {
goto fail;
}
@ -280,7 +286,7 @@ int event_reload(zone_t *zone)
}
/* Schedule notify and refresh after load. */
if (zone_master(zone)) {
if (!zone_is_master(zone)) {
zone_events_schedule(zone, ZONE_EVENT_REFRESH, ZONE_EVENT_NOW);
}
if (!zone_contents_is_empty(contents)) {
@ -289,12 +295,14 @@ int event_reload(zone_t *zone)
}
/* Schedule zone resign. */
if (zone->conf->dnssec_enable) {
conf_val_t val = conf_zone_get(conf(), C_DNSSEC_ENABLE, zone->name);
if (conf_bool(&val)) {
schedule_dnssec(zone, dnssec_refresh);
}
/* Periodic execution. */
zone_events_schedule(zone, ZONE_EVENT_FLUSH, zone_config->dbsync_timeout);
val = conf_zone_get(conf(), C_ZONEFILE_SYNC, zone->name);
zone_events_schedule(zone, ZONE_EVENT_FLUSH, conf_int(&val));
uint32_t current_serial = zone_contents_serial(zone->contents);
log_zone_info(zone->name, "loaded, serial %u -> %u",
@ -311,9 +319,16 @@ int event_refresh(zone_t *zone)
{
assert(zone);
const conf_iface_t *master = zone_master(zone);
if (master == NULL) {
/* If not slave zone, ignore. */
/* Ignore if master zone. */
if (zone_is_master(zone)) {
return KNOT_EOK;
}
/* Ignore if DNSSEC enabled. */
conf_val_t val = conf_zone_get(conf(), C_DNSSEC_ENABLE, zone->name);
if (conf_bool(&val)) {
log_zone_notice(zone->name, "ignoring zone refresh due to "
"enabled automatic DNSSEC signing.");
return KNOT_EOK;
}
@ -323,11 +338,12 @@ int event_refresh(zone_t *zone)
return KNOT_EOK;
}
int ret = zone_query_execute(zone, KNOT_QUERY_NORMAL, master);
const conf_remote_t master = zone_master(zone);
int ret = zone_query_execute(zone, KNOT_QUERY_NORMAL, &master);
const knot_rdataset_t *soa = zone_soa(zone);
if (ret != KNOT_EOK) {
/* Log connection errors. */
ZONE_QUERY_LOG(LOG_WARNING, zone, master, "SOA query, outgoing",
ZONE_QUERY_LOG(LOG_WARNING, zone, &master, "SOA query, outgoing",
"failed (%s)", knot_strerror(ret));
/* Rotate masters if current failed. */
zone_master_rotate(zone);
@ -346,9 +362,16 @@ int event_xfer(zone_t *zone)
{
assert(zone);
const conf_iface_t *master = zone_master(zone);
if (master == NULL) {
/* If not slave zone, ignore. */
/* Ignore if master zone. */
if (zone_is_master(zone)) {
return KNOT_EOK;
}
/* Ignore if DNSSEC enabled. */
conf_val_t val = conf_zone_get(conf(), C_DNSSEC_ENABLE, zone->name);
if (conf_bool(&val)) {
log_zone_notice(zone->name, "ignoring slave transfer due to "
"enabled automatic DNSSEC signing.");
return KNOT_EOK;
}
@ -360,7 +383,8 @@ int event_xfer(zone_t *zone)
}
/* Execute zone transfer and reschedule timers. */
int ret = zone_query_transfer(zone, master, pkt_type);
const conf_remote_t master = zone_master(zone);
int ret = zone_query_transfer(zone, &master, pkt_type);
/* Handle failure during transfer. */
if (ret != KNOT_EOK) {
@ -383,10 +407,12 @@ int event_xfer(zone_t *zone)
zone_events_schedule(zone, ZONE_EVENT_REFRESH, knot_soa_refresh(soa));
zone_events_schedule(zone, ZONE_EVENT_NOTIFY, ZONE_EVENT_NOW);
zone_events_cancel(zone, ZONE_EVENT_EXPIRE);
if (zone->conf->dbsync_timeout == 0) {
val = conf_zone_get(conf(), C_ZONEFILE_SYNC, zone->name);
int64_t dbsync_timeout = conf_int(&val);
if (dbsync_timeout == 0) {
zone_events_schedule(zone, ZONE_EVENT_FLUSH, ZONE_EVENT_NOW);
} else if (!zone_events_is_scheduled(zone, ZONE_EVENT_FLUSH)) {
zone_events_schedule(zone, ZONE_EVENT_FLUSH, zone->conf->dbsync_timeout);
zone_events_schedule(zone, ZONE_EVENT_FLUSH, dbsync_timeout);
}
/* Transfer cleanup. */
@ -451,7 +477,8 @@ int event_flush(zone_t *zone)
assert(zone);
/* Reschedule. */
int next_timeout = zone->conf->dbsync_timeout;
conf_val_t val = conf_zone_get(conf(), C_ZONEFILE_SYNC, zone->name);
int64_t next_timeout = conf_int(&val);
if (next_timeout > 0) {
zone_events_schedule(zone, ZONE_EVENT_FLUSH, next_timeout);
}
@ -474,19 +501,22 @@ int event_notify(zone_t *zone)
}
/* Walk through configured remotes and send messages. */
conf_remote_t *remote = 0;
WALK_LIST(remote, zone->conf->acl.notify_out) {
conf_iface_t *iface = remote->remote;
conf_val_t val = conf_zone_get(conf(), C_NOTIFY, zone->name);
while (val.code == KNOT_EOK) {
conf_remote_t remote = conf_remote(conf(), &val);
int ret = zone_query_execute(zone, KNOT_QUERY_NOTIFY, iface);
int ret = zone_query_execute(zone, KNOT_QUERY_NOTIFY, &remote);
if (ret == KNOT_EOK) {
ZONE_QUERY_LOG(LOG_INFO, zone, iface, "NOTIFY, outgoing",
"serial %u",
ZONE_QUERY_LOG(LOG_INFO, zone, &remote,
"NOTIFY, outgoing", "serial %u",
zone_contents_serial(zone->contents));
} else {
ZONE_QUERY_LOG(LOG_WARNING, zone, iface, "NOTIFY, outgoing",
"failed (%s)", knot_strerror(ret));
ZONE_QUERY_LOG(LOG_WARNING, zone, &remote,
"NOTIFY, outgoing", "failed (%s)",
knot_strerror(ret));
}
conf_val_next(&val);
}
return KNOT_EOK;
@ -515,7 +545,7 @@ int event_dnssec(zone_t *zone)
sign_flags = 0;
}
ret = knot_dnssec_zone_sign(zone->contents, zone->conf, &ch, sign_flags, &refresh_at);
ret = knot_dnssec_zone_sign(zone->contents, &ch, sign_flags, &refresh_at);
if (ret != KNOT_EOK) {
goto done;
}
@ -552,7 +582,8 @@ int event_dnssec(zone_t *zone)
schedule_dnssec(zone, refresh_at);
zone_events_schedule(zone, ZONE_EVENT_NOTIFY, ZONE_EVENT_NOW);
if (zone->conf->dbsync_timeout == 0) {
conf_val_t val = conf_zone_get(conf(), C_ZONEFILE_SYNC, zone->name);
if (conf_int(&val) == 0) {
zone_events_schedule(zone, ZONE_EVENT_FLUSH, ZONE_EVENT_NOW);
}
@ -573,3 +604,4 @@ uint32_t bootstrap_next(uint32_t timer)
}
return timer;
}

View file

@ -35,12 +35,12 @@ static void replan_event(zone_t *zone, const zone_t *old_zone, zone_event_type_t
/*!< \brief Replans events that are dependent on the SOA record. */
static void replan_soa_events(zone_t *zone, const zone_t *old_zone)
{
if (!zone_master(zone)) {
if (zone_is_master(zone)) {
// Events only valid for slaves.
return;
}
if (zone_master(old_zone)) {
if (!zone_is_master(old_zone)) {
// Replan SOA events.
replan_event(zone, old_zone, ZONE_EVENT_REFRESH);
replan_event(zone, old_zone, ZONE_EVENT_EXPIRE);
@ -58,12 +58,12 @@ static void replan_soa_events(zone_t *zone, const zone_t *old_zone)
/*!< \brief Replans transfer event. */
static void replan_xfer(zone_t *zone, const zone_t *old_zone)
{
if (!zone_master(zone)) {
if (zone_is_master(zone)) {
// Only valid for slaves.
return;
}
if (zone_master(old_zone)) {
if (!zone_is_master(old_zone)) {
// Replan the transfer from old zone.
replan_event(zone, old_zone, ZONE_EVENT_XFER);
} else if (zone_contents_is_empty(zone->contents)) {
@ -76,7 +76,9 @@ static void replan_xfer(zone_t *zone, const zone_t *old_zone)
/*!< \brief Replans flush event. */
static void replan_flush(zone_t *zone, const zone_t *old_zone)
{
if (zone->conf->dbsync_timeout <= 0) {
conf_val_t val = conf_zone_get(conf(), C_ZONEFILE_SYNC, zone->name);
int64_t dbsync_timeout = conf_int(&val);
if (dbsync_timeout <= 0) {
// Immediate sync scheduled after events.
return;
}
@ -84,12 +86,12 @@ static void replan_flush(zone_t *zone, const zone_t *old_zone)
const time_t flush_time = zone_events_get_time(old_zone, ZONE_EVENT_FLUSH);
if (flush_time <= ZONE_EVENT_NOW) {
// Not scheduled previously.
zone_events_schedule(zone, ZONE_EVENT_FLUSH, zone->conf->dbsync_timeout);
zone_events_schedule(zone, ZONE_EVENT_FLUSH, dbsync_timeout);
return;
}
// Pick time to schedule: either reuse or schedule sooner than old event.
const time_t schedule_at = MIN(time(NULL) + zone->conf->dbsync_timeout, flush_time);
const time_t schedule_at = MIN(time(NULL) + dbsync_timeout, flush_time);
zone_events_schedule_at(zone, ZONE_EVENT_FLUSH, schedule_at);
}
@ -109,7 +111,8 @@ static void duplicate_ddns_q(zone_t *zone, zone_t *old_zone)
/*!< Replans DNSSEC event. Not whole resign needed, \todo #247 */
static void replan_dnssec(zone_t *zone)
{
if (zone->conf->dnssec_enable) {
conf_val_t val = conf_zone_get(conf(), C_DNSSEC_ENABLE, zone->name);
if (conf_bool(&val)) {
/* Keys could have changed, force resign. */
zone_events_schedule(zone, ZONE_EVENT_DNSSEC, ZONE_EVENT_NOW);
}

View file

@ -38,9 +38,9 @@ int serial_compare(uint32_t s1, uint32_t s2)
int serial_next(uint32_t current, int policy)
{
switch (policy) {
case CONF_SERIAL_INCREMENT:
case SERIAL_POLICY_INCREMENT:
return current + 1;
case CONF_SERIAL_UNIXTIME:
case SERIAL_POLICY_UNIXTIME:
return time(NULL);
default:
assert(0);

View file

@ -31,7 +31,7 @@ int serial_compare(uint32_t s1, uint32_t s2);
* \brief Get next serial for given serial update policy.
*
* \param current Current SOA serial.
* \param policy CONF_SERIAL_INCREMENT or CONF_SERIAL_UNIXTIME.
* \param policy SERIAL_POLICY_INCREMENT or SERIAL_POLICY_UNIXTIME.
*
* \return New serial.
*/

View file

@ -14,7 +14,6 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "libknot/libknot.h"
#include "knot/common/log.h"
#include "knot/server/journal.h"
#include "knot/zone/zone-diff.h"
@ -23,15 +22,18 @@
#include "knot/zone/zonefile.h"
#include "knot/dnssec/zone-events.h"
#include "knot/updates/apply.h"
#include "libknot/rdata.h"
#include "libknot/libknot.h"
zone_contents_t *zone_load_contents(conf_zone_t *zone_config)
zone_contents_t *zone_load_contents(conf_t *conf, const knot_dname_t *zone_name)
{
assert(zone_config);
assert(conf);
assert(zone_name);
zloader_t zl;
int ret = zonefile_open(&zl, zone_config->file, zone_config->name,
zone_config->enable_checks);
char *zonefile = conf_zonefile(conf, zone_name);
conf_val_t val = conf_zone_get(conf, C_SEM_CHECKS, zone_name);
int ret = zonefile_open(&zl, zonefile, zone_name, conf_bool(&val));
free(zonefile);
if (ret != KNOT_EOK) {
return NULL;
}
@ -39,7 +41,7 @@ zone_contents_t *zone_load_contents(conf_zone_t *zone_config)
/* Set the zone type (master/slave). If zone has no master set, we
* are the primary master for this zone (i.e. zone type = master).
*/
zl.creator->master = !zone_load_can_bootstrap(zone_config);
zl.creator->master = !zone_load_can_bootstrap(conf, zone_name);
zone_contents_t *zone_contents = zonefile_load(&zl);
zonefile_close(&zl);
@ -51,7 +53,7 @@ zone_contents_t *zone_load_contents(conf_zone_t *zone_config)
}
/*! \brief Check zone configuration constraints. */
int zone_load_check(zone_contents_t *contents, conf_zone_t *zone_config)
int zone_load_check(conf_t *conf, zone_contents_t *contents)
{
/* Bootstrapped zone, no checks apply. */
if (contents == NULL) {
@ -62,11 +64,12 @@ int zone_load_check(zone_contents_t *contents, conf_zone_t *zone_config)
/* Check minimum EDNS0 payload if signed. (RFC4035/sec. 3) */
if (zone_contents_is_signed(contents)) {
if (conf()->max_udp_payload < KNOT_EDNS_MIN_DNSSEC_PAYLOAD) {
log_zone_warning(zone_name, "EDNS payload size is "
"lower than %u bytes for DNSSEC zone",
KNOT_EDNS_MIN_DNSSEC_PAYLOAD);
conf()->max_udp_payload = KNOT_EDNS_MIN_DNSSEC_PAYLOAD;
conf_val_t val = conf_get(conf, C_SRV, C_MAX_UDP_PAYLOAD);
if (conf_int(&val) < KNOT_EDNS_MIN_DNSSEC_PAYLOAD) {
log_zone_error(zone_name, "EDNS payload size is "
"lower than %u bytes for DNSSEC zone",
KNOT_EDNS_MIN_DNSSEC_PAYLOAD);
return KNOT_EPAYLOAD;
}
}
@ -84,11 +87,13 @@ int zone_load_check(zone_contents_t *contents, conf_zone_t *zone_config)
/*!
* \brief Apply changesets to zone from journal.
*/
int zone_load_journal(zone_t *zone, zone_contents_t *contents)
int zone_load_journal(conf_t *conf, zone_t *zone, zone_contents_t *contents)
{
/* Check if journal is used and zone is not empty. */
if (!journal_exists(zone->conf->ixfr_db) ||
char *journal_name = conf_journalfile(conf, zone->name);
if (!journal_exists(journal_name) ||
zone_contents_is_empty(contents)) {
free(journal_name);
return KNOT_EOK;
}
@ -100,8 +105,10 @@ int zone_load_journal(zone_t *zone, zone_contents_t *contents)
init_list(&chgs);
pthread_mutex_lock(&zone->journal_lock);
int ret = journal_load_changesets(zone, &chgs, serial, serial - 1);
int ret = journal_load_changesets(journal_name, zone, &chgs, serial,
serial - 1);
pthread_mutex_unlock(&zone->journal_lock);
free(journal_name);
if ((ret != KNOT_EOK && ret != KNOT_ERANGE) || EMPTY_LIST(chgs)) {
changesets_free(&chgs);
@ -124,14 +131,14 @@ int zone_load_journal(zone_t *zone, zone_contents_t *contents)
return ret;
}
int zone_load_post(zone_contents_t *contents, zone_t *zone, uint32_t *dnssec_refresh)
int zone_load_post(conf_t *conf, zone_contents_t *contents, zone_t *zone,
uint32_t *dnssec_refresh)
{
if (zone == NULL) {
return KNOT_EINVAL;
}
int ret = KNOT_EOK;
const conf_zone_t *conf = zone->conf;
changeset_t change;
ret = changeset_init(&change, zone->name);
if (ret != KNOT_EOK) {
@ -139,9 +146,12 @@ int zone_load_post(zone_contents_t *contents, zone_t *zone, uint32_t *dnssec_ref
}
/* Sign zone using DNSSEC (if configured). */
if (conf->dnssec_enable) {
assert(conf->build_diffs);
ret = knot_dnssec_zone_sign(contents, conf, &change, 0, dnssec_refresh);
conf_val_t val = conf_zone_get(conf, C_DNSSEC_ENABLE, zone->name);
bool dnssec_enable = conf_bool(&val);
val = conf_zone_get(conf, C_IXFR_DIFF, zone->name);
bool build_diffs = conf_bool(&val);
if (dnssec_enable) {
ret = knot_dnssec_zone_sign(contents, &change, 0, dnssec_refresh);
if (ret != KNOT_EOK) {
changeset_clear(&change);
return ret;
@ -160,9 +170,9 @@ int zone_load_post(zone_contents_t *contents, zone_t *zone, uint32_t *dnssec_ref
}
}
/* Calculate IXFR from differences (if configured). */
/* Calculate IXFR from differences (if configured or auto DNSSEC). */
const bool contents_changed = zone->contents && (contents != zone->contents);
if (contents_changed && conf->build_diffs) {
if (contents_changed && (build_diffs || dnssec_enable)) {
/* Replace changes from zone signing, the resulting diff will cover
* those changes as well. */
changeset_clear(&change);
@ -197,7 +207,10 @@ int zone_load_post(zone_contents_t *contents, zone_t *zone, uint32_t *dnssec_ref
return ret;
}
bool zone_load_can_bootstrap(const conf_zone_t *zone_config)
bool zone_load_can_bootstrap(conf_t *conf, const knot_dname_t *zone_name)
{
return zone_config && !EMPTY_LIST(zone_config->acl.xfr_in);
conf_val_t val = conf_zone_get(conf, C_MASTER, zone_name);
size_t count = conf_val_count(&val);
return count > 0;
}

View file

@ -24,40 +24,47 @@
/*!
* \brief Load zone contents according to the configuration.
*
* \param zone_config
* \param conf
* \param zone_name
* \return new zone contents or NULL
*/
zone_contents_t *zone_load_contents(conf_zone_t *zone_config);
zone_contents_t *zone_load_contents(conf_t *conf, const knot_dname_t *zone_name);
/*!
* \brief Check loaded zone contents validity.
*
* \param conf
* \param contents
* \param zone_config
* \return KNOT_EOK or an error
*/
int zone_load_check(zone_contents_t *contents, conf_zone_t *zone_config);
int zone_load_check(conf_t *conf, zone_contents_t *contents);
/*!
* \brief Update zone contents from the journal.
*
* \param conf
* \param zone
* \param contents
* \return KNOT_EOK or an error
*/
int zone_load_journal(zone_t *zone, zone_contents_t *contents);
int zone_load_journal(conf_t *conf, zone_t *zone, zone_contents_t *contents);
/*!
* \brief Zone loading post-actions (zone resign, calculation of delta)
*
* \param conf
* \param contents
* \param zone
* \param dnssec_refresh
* \return KNOT_EOK or an error
*/
int zone_load_post(zone_contents_t *contents, zone_t *zone, uint32_t *dnssec_refresh);
int zone_load_post(conf_t *conf, zone_contents_t *contents, zone_t *zone,
uint32_t *dnssec_refresh);
/*!
* \brief Check if zone can be bootstrapped.
*
* \param conf
* \param zone_name
*/
bool zone_load_can_bootstrap(const conf_zone_t *zone_config);
bool zone_load_can_bootstrap(conf_t *conf, const knot_dname_t *zone_name);

View file

@ -18,11 +18,13 @@
#include <assert.h>
#include <string.h>
#include <sys/stat.h>
#include <urcu.h>
#include "dnssec/random.h"
#include "libknot/descriptor.h"
#include "knot/common/evsched.h"
#include "libknot/internal/lists.h"
#include "knot/common/log.h"
#include "knot/common/trim.h"
#include "knot/zone/node.h"
#include "knot/zone/serial.h"
@ -35,8 +37,11 @@
#include "libknot/libknot.h"
#include "libknot/dname.h"
#include "libknot/internal/utils.h"
#include "libknot/internal/mem.h"
#include "libknot/rrtype/soa.h"
#define JOURNAL_SUFFIX ".diff.db"
static void free_ddns_queue(zone_t *z)
{
struct knot_request *n = NULL;
@ -49,28 +54,20 @@ static void free_ddns_queue(zone_t *z)
}
}
zone_t* zone_new(conf_zone_t *conf)
zone_t* zone_new(const knot_dname_t *name)
{
if (!conf) {
return NULL;
}
zone_t *zone = malloc(sizeof(zone_t));
if (zone == NULL) {
return NULL;
}
memset(zone, 0, sizeof(zone_t));
zone->name = knot_dname_from_str_alloc(conf->name);
knot_dname_to_lower(zone->name);
zone->name = knot_dname_copy(name, NULL);
if (zone->name == NULL) {
free(zone);
return NULL;
}
// Configuration
zone->conf = conf;
// DDNS
pthread_mutex_init(&zone->ddns_lock, NULL);
zone->ddns_queue_size = 0;
@ -101,9 +98,6 @@ void zone_free(zone_t **zone_ptr)
pthread_mutex_destroy(&zone->ddns_lock);
pthread_mutex_destroy(&zone->journal_lock);
/* Free assigned config. */
conf_free_zone(zone->conf);
/* Free zone contents. */
zone_contents_deep_free(&zone->contents);
@ -116,21 +110,25 @@ int zone_change_store(zone_t *zone, changeset_t *change)
assert(zone);
assert(change);
conf_zone_t *conf = zone->conf;
conf_val_t val = conf_zone_get(conf(), C_IXFR_FSLIMIT, zone->name);
int64_t ixfr_fslimit = conf_int(&val);
char *journal_file = conf_journalfile(conf(), zone->name);
pthread_mutex_lock(&zone->journal_lock);
int ret = journal_store_changeset(change, conf->ixfr_db, conf->ixfr_fslimit);
int ret = journal_store_changeset(change, journal_file, ixfr_fslimit);
if (ret == KNOT_EBUSY) {
log_zone_notice(zone->name, "journal is full, flushing");
/* Transaction rolled back, journal released, we may flush. */
ret = zone_flush_journal(zone);
if (ret == KNOT_EOK) {
ret = journal_store_changeset(change, conf->ixfr_db, conf->ixfr_fslimit);
ret = journal_store_changeset(change, journal_file, ixfr_fslimit);
}
}
pthread_mutex_unlock(&zone->journal_lock);
free(journal_file);
return ret;
}
@ -139,22 +137,26 @@ int zone_changes_store(zone_t *zone, list_t *chgs)
assert(zone);
assert(chgs);
conf_zone_t *conf = zone->conf;
conf_val_t val = conf_zone_get(conf(), C_IXFR_FSLIMIT, zone->name);
int64_t ixfr_fslimit = conf_int(&val);
char *journal_file = conf_journalfile(conf(), zone->name);
pthread_mutex_lock(&zone->journal_lock);
int ret = journal_store_changesets(chgs, conf->ixfr_db, conf->ixfr_fslimit);
int ret = journal_store_changesets(chgs, journal_file, ixfr_fslimit);
if (ret == KNOT_EBUSY) {
log_zone_notice(zone->name, "journal is full, flushing");
/* Transaction rolled back, journal released, we may flush. */
ret = zone_flush_journal(zone);
if (ret == KNOT_EOK) {
ret = journal_store_changesets(chgs, conf->ixfr_db, conf->ixfr_fslimit);
ret = journal_store_changesets(chgs, journal_file, ixfr_fslimit);
}
}
pthread_mutex_unlock(&zone->journal_lock);
free(journal_file);
return ret;
}
@ -171,29 +173,35 @@ zone_contents_t *zone_switch_contents(zone_t *zone, zone_contents_t *new_content
return old_contents;
}
const conf_iface_t *zone_master(const zone_t *zone)
bool zone_is_master(const zone_t *zone)
{
if (zone == NULL) {
return NULL;
}
if (EMPTY_LIST(zone->conf->acl.xfr_in)) {
return NULL;
}
conf_remote_t *master = HEAD(zone->conf->acl.xfr_in);
return master->remote;
conf_val_t val = conf_zone_get(conf(), C_MASTER, zone->name);
return conf_val_count(&val) > 0 ? false : true;
}
void zone_master_rotate(const zone_t *zone)
conf_remote_t zone_master(const zone_t *zone)
{
conf_val_t val = conf_zone_get(conf(), C_MASTER, zone->name);
list_t *master_list = &zone->conf->acl.xfr_in;
if (list_size(master_list) < 2) {
return;
/* Seek the current master if possible. */
if (zone->master_index < conf_val_count(&val)) {
for (size_t index = 0; index < zone->master_index; index++) {
conf_val_next(&val);
}
}
add_tail(master_list, HEAD(*master_list));
return conf_remote(conf(), &val);
}
void zone_master_rotate(zone_t *zone)
{
conf_val_t val = conf_zone_get(conf(), C_MASTER, zone->name);
if (zone->master_index + 2 <= conf_val_count(&val)) {
zone->master_index += 1;
} else {
zone->master_index = 0;
}
}
int zone_flush_journal(zone_t *zone)
@ -213,35 +221,44 @@ int zone_flush_journal(zone_t *zone)
/* Fetch zone source (where it came from). */
const struct sockaddr_storage *from = NULL;
const conf_iface_t *master = zone_master(zone);
if (master != NULL) {
from = &master->addr;
if (!zone_is_master(zone)) {
const conf_remote_t master = zone_master(zone);
from = &master.addr;
}
char *zonefile = conf_zonefile(conf(), zone->name);
/* Synchronize journal. */
conf_zone_t *conf = zone->conf;
int ret = zonefile_write(conf->file, contents, from);
int ret = zonefile_write(zonefile, contents, from);
if (ret == KNOT_EOK) {
log_zone_info(zone->name, "zone file updated, serial %u -> %u",
zone->zonefile_serial, serial_to);
} else {
log_zone_warning(zone->name, "failed to update zone file (%s)",
knot_strerror(ret));
free(zonefile);
return ret;
}
/* Update zone version. */
struct stat st;
if (stat(zone->conf->file, &st) < 0) {
if (stat(zonefile, &st) < 0) {
log_zone_warning(zone->name, "failed to update zone file (%s)",
knot_strerror(KNOT_EACCES));
free(zonefile);
return KNOT_EACCES;
}
free(zonefile);
char *journal_file = conf_journalfile(conf(), zone->name);
/* Update zone file serial and journal. */
zone->zonefile_mtime = st.st_mtime;
zone->zonefile_serial = serial_to;
journal_mark_synced(zone->conf->ixfr_db);
journal_mark_synced(journal_file);
free(journal_file);
/* Trim extra heap. */
mem_trim();

View file

@ -36,6 +36,7 @@
#include "knot/zone/events/events.h"
#include "knot/zone/contents.h"
#include "libknot/dname.h"
#include "libknot/packet/pkt.h"
struct process_query_param;
@ -54,7 +55,6 @@ typedef struct zone
{
knot_dname_t *name;
zone_contents_t *contents;
conf_zone_t *conf;
zone_flag_t flags;
/*! \brief DDNS queue and lock. */
@ -71,6 +71,8 @@ typedef struct zone
time_t zonefile_mtime;
uint32_t zonefile_serial;
/*! \brief Config master list index of the current master server. */
size_t master_index;
} zone_t;
/*----------------------------------------------------------------------------*/
@ -78,11 +80,11 @@ typedef struct zone
/*!
* \brief Creates new zone with emtpy zone content.
*
* \param conf Zone configuration.
* \param name Zone name.
*
* \return The initialized zone structure or NULL if an error occured.
*/
zone_t *zone_new(conf_zone_t *conf);
zone_t* zone_new(const knot_dname_t *name);
/*!
* \brief Deallocates the zone structure.
@ -106,11 +108,14 @@ int zone_change_store(zone_t *zone, changeset_t *change);
zone_contents_t *zone_switch_contents(zone_t *zone,
zone_contents_t *new_contents);
/*! \brief Return zone master remote. */
const conf_iface_t *zone_master(const zone_t *zone);
/*! \brief Check if the zone has some masters. */
bool zone_is_master(const zone_t *zone);
/*! \brief Rotate list of master remotes for current zone. */
void zone_master_rotate(const zone_t *zone);
/*! \brief Return the current zone master. */
conf_remote_t zone_master(const zone_t *zone);
/*! \brief Set the next zone master as a current. */
void zone_master_rotate(zone_t *zone);
/*! \brief Synchronize zone file with journal. */
int zone_flush_journal(zone_t *zone);

View file

@ -16,18 +16,18 @@
#include <assert.h>
#include <sys/stat.h>
#include <urcu.h>
#include "libknot/libknot.h"
#include "knot/zone/zonedb-load.h"
#include "knot/zone/zone-load.h"
#include "knot/conf/conf.h"
#include "libknot/rrtype/soa.h"
#include "knot/zone/zone.h"
#include "knot/zone/zonefile.h"
#include "knot/zone/zonedb.h"
#include "knot/zone/timers.h"
#include "knot/server/server.h"
#include "libknot/dname.h"
#include "knot/common/log.h"
#include "libknot/libknot.h"
/*- zone file status --------------------------------------------------------*/
@ -50,12 +50,15 @@ typedef enum {
*
* \return Zone status.
*/
static zone_status_t zone_file_status(const zone_t *old_zone,
const conf_zone_t *conf)
static zone_status_t zone_file_status(const zone_t *old_zone, conf_t *conf,
const knot_dname_t *name)
{
assert(conf);
assert(name);
time_t mtime = zonefile_mtime(conf->file);
char *zonefile = conf_zonefile(conf, name);
time_t mtime = zonefile_mtime(zonefile);
free(zonefile);
if (mtime < 0) {
// Zone file does not exist.
@ -63,8 +66,8 @@ static zone_status_t zone_file_status(const zone_t *old_zone,
// Deferred flush.
return ZONE_STATUS_FOUND_CURRENT;
} else {
return zone_load_can_bootstrap(conf) ? ZONE_STATUS_BOOSTRAP \
: ZONE_STATUS_NOT_FOUND;
return zone_load_can_bootstrap(conf, name) ?
ZONE_STATUS_BOOSTRAP : ZONE_STATUS_NOT_FOUND;
}
} else {
// Zone file exists.
@ -84,14 +87,11 @@ static zone_status_t zone_file_status(const zone_t *old_zone,
* \brief Log message about loaded zone (name and status).
*
* \param zone Zone structure.
* \param zone_name Printable name of the zone.
* \param status Zone file status.
*/
static void log_zone_load_info(const zone_t *zone, const char *zone_name,
zone_status_t status)
static void log_zone_load_info(const zone_t *zone, zone_status_t status)
{
assert(zone);
assert(zone_name);
const char *action = NULL;
@ -114,9 +114,9 @@ static void log_zone_load_info(const zone_t *zone, const char *zone_name,
log_zone_info(zone->name, "zone %s, serial %u", action, serial);
}
static zone_t *create_zone_from(conf_zone_t *zone_conf, server_t *server)
static zone_t *create_zone_from(const knot_dname_t *name, server_t *server)
{
zone_t *zone = zone_new(zone_conf);
zone_t *zone = zone_new(name);
if (!zone) {
return NULL;
}
@ -124,7 +124,6 @@ static zone_t *create_zone_from(conf_zone_t *zone_conf, server_t *server)
int result = zone_events_setup(zone, server->workers, &server->sched,
server->timers_db);
if (result != KNOT_EOK) {
zone->conf = NULL;
zone_free(&zone);
return NULL;
}
@ -132,16 +131,16 @@ static zone_t *create_zone_from(conf_zone_t *zone_conf, server_t *server)
return zone;
}
static zone_t *create_zone_reload(conf_zone_t *zone_conf, server_t *server,
zone_t *old_zone)
static zone_t *create_zone_reload(conf_t *conf, const knot_dname_t *name,
server_t *server, zone_t *old_zone)
{
zone_t *zone = create_zone_from(zone_conf, server);
zone_t *zone = create_zone_from(name, server);
if (!zone) {
return NULL;
}
zone->contents = old_zone->contents;
const zone_status_t zstatus = zone_file_status(old_zone, zone_conf);
const zone_status_t zstatus = zone_file_status(old_zone, conf, name);
switch (zstatus) {
case ZONE_STATUS_FOUND_UPDATED:
@ -177,7 +176,7 @@ static void reuse_events(zone_t *zone, const time_t *timers)
// Timer unset.
continue;
}
if (slave_event(event) && !zone_master(zone)) {
if (slave_event(event) && zone_is_master(zone)) {
// Slave-only event.
continue;
}
@ -192,9 +191,10 @@ static bool zone_expired(const time_t *timers)
return now <= timers[ZONE_EVENT_EXPIRE];
}
static zone_t *create_zone_new(conf_zone_t *zone_conf, server_t *server)
static zone_t *create_zone_new(conf_t * conf, const knot_dname_t *name,
server_t *server)
{
zone_t *zone = create_zone_from(zone_conf, server);
zone_t *zone = create_zone_from(name, server);
if (!zone) {
return NULL;
}
@ -207,14 +207,13 @@ static zone_t *create_zone_new(conf_zone_t *zone_conf, server_t *server)
if (ret != KNOT_EOK) {
log_zone_error(zone->name, "cannot read zone timers (%s)",
knot_strerror(ret));
zone->conf = NULL;
zone_free(&zone);
return NULL;
}
reuse_events(zone, timers);
const zone_status_t zstatus = zone_file_status(NULL, zone_conf);
const zone_status_t zstatus = zone_file_status(NULL, conf, name);
switch (zstatus) {
case ZONE_STATUS_FOUND_NEW:
@ -235,7 +234,7 @@ static zone_t *create_zone_new(conf_zone_t *zone_conf, server_t *server)
assert(0);
}
log_zone_load_info(zone, zone_conf->name, zstatus);
log_zone_load_info(zone, zstatus);
return zone;
}
@ -243,22 +242,23 @@ static zone_t *create_zone_new(conf_zone_t *zone_conf, server_t *server)
/*!
* \brief Load or reload the zone.
*
* \param zone_conf Zone configuration.
* \param conf Configuration.
* \param server Server.
* \param old_zone Already loaded zone (can be NULL).
*
* \return Error code, KNOT_EOK if successful.
*/
static zone_t *create_zone(conf_zone_t *zone_conf, server_t *server,
static zone_t *create_zone(conf_t *conf, const knot_dname_t *name, server_t *server,
zone_t *old_zone)
{
assert(zone_conf);
assert(conf);
assert(name);
assert(server);
if (old_zone) {
return create_zone_reload(zone_conf, server, old_zone);
return create_zone_reload(conf, name, server, old_zone);
} else {
return create_zone_new(zone_conf, server);
return create_zone_new(conf, name, server);
}
}
@ -273,37 +273,31 @@ static zone_t *create_zone(conf_zone_t *zone_conf, server_t *server,
*
* \return New zone database.
*/
static knot_zonedb_t *create_zonedb(const conf_t *conf, server_t *server)
static knot_zonedb_t *create_zonedb(conf_t *conf, server_t *server)
{
assert(conf);
assert(server);
knot_zonedb_t *db_old = server->zone_db;
knot_zonedb_t *db_new = knot_zonedb_new(hattrie_weight(conf->zones));
knot_zonedb_t *db_new = knot_zonedb_new(conf_id_count(conf, C_ZONE));
if (!db_new) {
return NULL;
}
hattrie_iter_t *it = hattrie_iter_begin(conf->zones, false);
for (; !hattrie_iter_finished(it); hattrie_iter_next(it)) {
conf_zone_t *zone_config = (conf_zone_t *)*hattrie_iter_val(it);
knot_dname_t *apex = knot_dname_from_str_alloc(zone_config->name);
zone_t *old_zone = knot_zonedb_find(db_old, apex);
knot_dname_free(&apex, NULL);
zone_t *zone = create_zone(zone_config, server, old_zone);
conf_iter_t iter = conf_iter(conf, C_ZONE);
while (iter.code == KNOT_EOK) {
conf_val_t id = conf_iter_id(conf, &iter);
zone_t *old_zone = knot_zonedb_find(db_old, conf_dname(&id));
zone_t *zone = create_zone(conf, conf_dname(&id), server, old_zone);
if (!zone) {
log_zone_str_error(zone_config->name,
"zone cannot be created");
conf_free_zone(zone_config);
log_zone_error(id.data, "zone cannot be created");
continue;
}
knot_zonedb_insert(db_new, zone);
conf_iter_next(conf, &iter);
}
hattrie_iter_free(it);
conf_iter_finish(conf, &iter);
return db_new;
}
@ -347,7 +341,7 @@ static int remove_old_zonedb(const knot_zonedb_t *db_new, knot_zonedb_t *db_old)
/*!
* \brief Update zone database according to configuration.
*/
int zonedb_reload(const conf_t *conf, struct server *server)
int zonedb_reload(conf_t *conf, struct server *server)
{
/* Check parameters */
if (conf == NULL || server == NULL) {

View file

@ -31,4 +31,4 @@ struct server;
* \retval KNOT_EINVAL
* \retval KNOT_ERROR
*/
int zonedb_reload(const conf_t *conf, struct server *server);
int zonedb_reload(conf_t *conf, struct server *server);

View file

@ -187,23 +187,8 @@ static void scanner_process(zs_scanner_t *scanner)
knot_rdataset_clear(&rr.rrs, NULL);
}
static zone_contents_t *create_zone_from_name(const char *origin)
{
if (origin == NULL) {
return NULL;
}
knot_dname_t *owner = knot_dname_from_str_alloc(origin);
if (owner == NULL) {
return NULL;
}
knot_dname_to_lower(owner);
zone_contents_t *z = zone_contents_new(owner);
knot_dname_free(&owner, NULL);
return z;
}
int zonefile_open(zloader_t *loader, const char *source, const char *origin,
bool semantic_checks)
int zonefile_open(zloader_t *loader, const char *source,
const knot_dname_t *origin, bool semantic_checks)
{
if (!loader) {
return KNOT_EINVAL;
@ -221,24 +206,32 @@ int zonefile_open(zloader_t *loader, const char *source, const char *origin,
}
memset(zc, 0, sizeof(zcreator_t));
zc->z = create_zone_from_name(origin);
zc->z = zone_contents_new(origin);
if (zc->z == NULL) {
free(zc);
return KNOT_ENOMEM;
}
/* Prepare textual owner for zone scanner. */
char *origin_str = knot_dname_to_str_alloc(origin);
if (origin_str == NULL) {
free(zc);
return KNOT_ENOMEM;
}
/* Create file loader. */
memset(loader, 0, sizeof(zloader_t));
loader->scanner = zs_scanner_create(origin, KNOT_CLASS_IN, 3600,
loader->scanner = zs_scanner_create(origin_str, KNOT_CLASS_IN, 3600,
scanner_process, process_error,
zc);
if (loader->scanner == NULL) {
free(origin_str);
free(zc);
return KNOT_ERROR;
}
loader->source = strdup(source);
loader->origin = strdup(origin);
loader->origin = origin_str;
loader->creator = zc;
loader->semantic_checks = semantic_checks;

View file

@ -65,8 +65,8 @@ typedef struct zloader {
* \retval Initialized loader on success.
* \retval NULL on error.
*/
int zonefile_open(zloader_t *loader, const char *source, const char *origin,
bool semantic_checks);
int zonefile_open(zloader_t *loader, const char *source,
const knot_dname_t *origin, bool semantic_checks);
/*!
* \brief Loads zone from a zone file.

View file

@ -69,7 +69,7 @@ static const struct error errors[] = {
{ KNOT_ENOZONE, "no such zone found" },
{ KNOT_ENONODE, "no such node in zone found" },
{ KNOT_EDNAMEPTR, "domain name pointer larger than allowed" },
{ KNOT_EPAYLOAD, "payload in OPT RR larger than max wire size" },
{ KNOT_EPAYLOAD, "invalid EDNS payload size" },
{ KNOT_EPREREQ, "UPDATE prerequisity not met" },
{ KNOT_ETTL, "TTL mismatch" },
{ KNOT_ENOXFR, "transfer was not sent" },

View file

@ -358,7 +358,7 @@ size_t knot_tsig_rdata_tsig_timers_length()
_public_
size_t knot_tsig_wire_maxsize(const knot_tsig_key_t *key)
{
if (key == NULL) {
if (key == NULL || key->name == NULL) {
return 0;
}

View file

@ -58,7 +58,7 @@ enum tsig_consts {
/*! \brief Packet signing context.
* \todo This should be later moved to TSIG files when refactoring. */
typedef struct knot_sign_context {
knot_tsig_key_t *tsig_key;
knot_tsig_key_t tsig_key;
uint8_t *tsig_buf;
uint8_t *tsig_digest;
size_t tsig_buflen;

View file

@ -14,6 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "libknot/internal/macros.h"
#include "libknot/yparser/yptrafo.h"
#include "libknot/libknot.h"
@ -73,6 +74,7 @@ static int format_item(
return KNOT_EOK;
}
_public_
int yp_format_key0(
const yp_item_t *item,
const uint8_t *data,
@ -87,6 +89,7 @@ int yp_format_key0(
first_value, last_value);
}
_public_
int yp_format_id(
const yp_item_t *item,
const uint8_t *data,
@ -103,6 +106,7 @@ int yp_format_id(
true, true);
}
_public_
int yp_format_key1(
const yp_item_t *item,
const uint8_t *data,

View file

@ -1,12 +1,12 @@
#!/usr/bin/env python3
'''Test for SOA events and planning thereof'''
'''Test for SOA events and planning thereof without NOTIFY'''
from dnstest.utils import *
from dnstest.test import Test
import random
EXPIRE_SLEEP = 4
EXPIRE_SLEEP = 6
def test_refresh(slave):
resp = slave.dig("example.", "SOA")
@ -14,7 +14,7 @@ def test_refresh(slave):
t.sleep(EXPIRE_SLEEP)
resp = slave.dig("example.", "SOA")
resp.check(rcode="NOERROR")
def test_expire(slave):
resp = slave.dig("example.", "SOA")
resp.check(rcode="NOERROR")
@ -27,6 +27,7 @@ def create_servers(t):
for _ in range(3):
master = t.server("bind")
master.disable_notify = True
master.max_conn_idle = "1s"
slave = t.server("knot")
slave.disable_notify = True
@ -112,14 +113,14 @@ t = Test()
random.seed()
# this zone has refresh = 1s, retry = 1s and expire = 1s + 2s for connection timeouts
# This zone has refresh = 1s, retry = 1s and expire = 2s
zone = t.zone("example.", storage=".")
servers = create_servers(t)
t.start()
#stop the servers so that the zone does not expire
# Stop the servers so that the zone does not expire
for server_pair in servers:
server_pair[0].stop()
server_pair[1].stop()

View file

@ -13,12 +13,12 @@ def break_xfrout(server):
config = f.read()
f.seek(0)
f.truncate()
config = config.replace("xfr-out ", "#xfr-out ")
config = config.replace(" acl:", " #acl:")
f.write(config)
t = Test(tsig=False)
# this zone has refresh = 1s, retry = 1s and expire = 10s + 2s for connection timeouts
# this zone has refresh = 1s, retry = 1s and expire = 8s
zone = t.zone("example.", storage=".")
EXPIRE_SLEEP = 15

View file

@ -5,7 +5,7 @@
from dnstest.test import Test
import random
EXPIRE_SLEEP = 17
EXPIRE_SLEEP = 20
RETRY_SLEEP = 10
START_SLEEP = 5
@ -104,7 +104,7 @@ def refresh_tests(t, zone, master, slave):
t = Test()
# this zone has refresh = 1s, retry = 1s and expire = 1s + 2s for connection timeouts
# this zone has refresh = 1s, retry = 1s and expire = 16s
zone = t.zone("example.", storage=".")
master = t.server("knot")

View file

@ -33,29 +33,27 @@ class KnotConf(object):
def __init__(self):
self.conf = ""
self.indent = ""
def sub(self):
self.indent += "\t"
def unsub(self):
self.indent = self.indent[:-1]
self.first_item = True
def begin(self, name):
self.conf += "%s%s {\n" % (self.indent, name)
self.sub()
self.conf += "%s:\n" % name
self.first_item = True
def end(self):
self.unsub()
self.conf += "%s}\n" % (self.indent)
if not self.indent:
self.conf += "\n"
self.conf += "\n"
def item(self, name, value):
self.conf += "%s%s %s;\n" % (self.indent, name, value)
self.conf += " %s: %s\n" % (name, value)
def item_str(self, name, value):
self.conf += "%s%s \"%s\";\n" % (self.indent, name, value)
self.conf += " %s: \"%s\"\n" % (name, value)
def id_item(self, name, value):
if not self.first_item:
self.conf += "\n"
else:
self.first_item = False
self.conf += " - %s: \"%s\"\n" % (name, value)
class BindConf(object):
'''Bind server config generator'''
@ -775,11 +773,13 @@ class Bind(Server):
s.item("type", "slave")
if self.tsig:
s.item("allow-notify", "{ key %s; }" % z.master.tsig.name)
if not z.master.disable_notify:
s.item("allow-notify", "{ key %s; }" % z.master.tsig.name)
s.item("masters", "{ %s port %i key %s; }" \
% (z.master.addr, z.master.port, z.master.tsig.name))
else:
s.item("allow-notify", "{ %s; }" % z.master.addr)
if not z.master.disable_notify:
s.item("allow-notify", "{ %s; }" % z.master.addr)
s.item("masters", "{ %s port %i; }" \
% (z.master.addr, z.master.port))
else:
@ -792,12 +792,15 @@ class Bind(Server):
if z.slaves:
slaves = ""
for slave in z.slaves:
if slave.disable_notify:
continue
if self.tsig:
slaves += "%s port %i key %s; " \
% (slave.addr, slave.port, self.tsig.name)
else:
slaves += "%s port %i; " % (slave.addr, slave.port)
s.item("also-notify", "{ %s}" % slaves)
if slaves:
s.item("also-notify", "{ %s}" % slaves)
if z.ddns:
if self.tsig:
@ -844,154 +847,174 @@ class Knot(Server):
def _on_str_hex(self, conf, name, value):
if value == True:
conf.item(name, "on")
conf.item_str(name, "")
elif value == False:
conf.item(name, "off")
return
elif value:
if isinstance(value, int) or value[:2] == "0x":
conf.item(name, value)
else:
conf.item_str(name, value)
conf.item_str(name, value)
def _key(self, conf, key):
conf.id_item("id", key.name)
conf.item_str("algorithm", key.alg)
conf.item_str("secret", key.key)
def get_config(self):
s = KnotConf()
s.begin("system")
s.begin("server")
self._on_str_hex(s, "identity", self.ident)
self._on_str_hex(s, "version", self.version)
self._on_str_hex(s, "nsid", self.nsid)
self._on_str_hex(s, "rate-limit", self.ratelimit)
s.item_str("rundir", self.dir)
s.item_str("listen", "%s@%s" % (self.addr, self.port))
if (self.max_conn_idle):
s.item("max-conn-idle", self.max_conn_idle)
s.item_str("max-conn-idle", self.max_conn_idle)
if (self.ratelimit):
s.item_str("rate-limit", self.ratelimit)
s.end()
s.begin("control")
s.item_str("listen-on", "knot.sock")
s.end()
s.begin("interfaces")
if self.ip == 4:
s.begin("ipv4")
else:
s.begin("ipv6")
s.item("address", self.addr)
s.item("port", self.port)
s.end()
s.item_str("listen", "knot.sock")
s.end()
if self.tsig:
s.begin("keys")
t = self.tsig
s.item_str("\"%s\" %s" % (t.name, t.alg), t.key)
t = self.tsig_test
s.item_str("\"%s\" %s" % (t.name, t.alg), t.key)
s.begin("key")
self._key(s, self.tsig)
self._key(s, self.tsig_test)
keys = set() # Duplicy check.
for zone in sorted(self.zones):
z = self.zones[zone]
if z.master and z.master.tsig.name not in keys:
t = z.master.tsig
s.item_str("\"%s\" %s" % (t.name, t.alg), t.key)
self._key(s, t)
keys.add(t.name)
for slave in z.slaves:
if slave.tsig and slave.tsig.name not in keys:
t = slave.tsig
s.item_str("\"%s\" %s" % (t.name, t.alg), t.key)
self._key(s, t)
keys.add(t.name)
s.end()
s.begin("remotes")
s.begin("local")
s.item("address", self.addr)
have_remote = False
servers = set() # Duplicity check.
for zone in sorted(self.zones):
z = self.zones[zone]
if z.master and z.master.name not in servers:
if not have_remote:
s.begin("remote")
have_remote = True
s.id_item("id", z.master.name)
s.item_str("address", "%s@%s" % (z.master.addr, z.master.port))
if z.master.tsig:
s.item_str("key", z.master.tsig.name)
servers.add(z.master.name)
for slave in z.slaves:
if slave.name not in servers:
if not have_remote:
s.begin("remote")
have_remote = True
s.id_item("id", slave.name)
s.item_str("address", "%s@%s" % (slave.addr, slave.port))
if slave.tsig:
s.item_str("key", slave.tsig.name)
servers.add(slave.name)
if have_remote:
s.end()
s.begin("acl")
s.id_item("id", "acl_local")
s.item_str("address", self.addr)
if self.tsig:
s.item_str("key", self.tsig.name)
s.end()
s.begin("test")
s.item("address", self.addr)
s.item("action", "[xfer, notify, update]")
s.id_item("id", "acl_test")
s.item_str("address", self.addr)
if self.tsig_test:
s.item_str("key", self.tsig_test.name)
s.end()
s.item("action", "[xfer, notify, update]")
servers = set() # Duplicity check.
for zone in sorted(self.zones):
z = self.zones[zone]
if z.master and z.master.name not in servers:
s.begin(z.master.name)
s.item("address", z.master.addr)
s.item("port", z.master.port)
s.id_item("id", "acl_%s" % z.master.name)
s.item_str("address", z.master.addr)
if z.master.tsig:
s.item_str("key", z.master.tsig.name)
s.end()
s.item("action", "notify")
servers.add(z.master.name)
for slave in z.slaves:
if slave.name not in servers:
s.begin(slave.name)
s.item("address", slave.addr)
s.item("port", slave.port)
if slave.tsig:
s.item_str("key", self.tsig.name)
s.end()
servers.add(slave.name)
if slave.name in servers:
continue
s.id_item("id", "acl_%s" % slave.name)
s.item_str("address", slave.addr)
if slave.tsig:
s.item_str("key", slave.tsig.name)
s.item("action", "xfer")
servers.add(slave.name)
s.end()
s.begin("zones")
s.begin("template")
s.id_item("id", "default")
s.item_str("storage", self.dir)
if self.zonefile_sync:
s.item("zonefile-sync", self.zonefile_sync)
s.item_str("zonefile-sync", self.zonefile_sync)
else:
s.item("zonefile-sync", "1d")
s.item_str("zonefile-sync", "1d")
if self.ixfr_fslimit:
s.item("ixfr-fslimit", self.ixfr_fslimit)
s.item("notify-timeout", "5")
s.item("notify-retries", "5")
s.item("semantic-checks", "on")
s.item_str("ixfr-fslimit", self.ixfr_fslimit)
s.item_str("notify-timeout", "5")
s.item_str("notify-retries", "5")
s.item_str("semantic-checks", "on")
if self.disable_any:
s.item("disable-any", "on")
s.item_str("disable-any", "on")
if self.dnssec_enable:
s.item_str("dnssec-keydir", self.keydir)
s.item("dnssec-enable", "on")
s.item_str("dnssec-enable", "on")
s.end()
s.begin("zone")
for zone in sorted(self.zones):
z = self.zones[zone]
s.begin(z.name)
s.id_item("domain", z.name)
s.item_str("file", z.zfile.path)
acl = ""
if z.master:
if not self.disable_notify:
s.item("notify-in", z.master.name)
s.item("xfr-in", z.master.name)
s.item("master", z.master.name)
if not z.master.disable_notify:
acl = "acl_%s" % z.master.name
slaves = ""
if z.slaves:
slaves = ""
for slave in z.slaves:
if slave.disable_notify:
continue
if slaves:
slaves += ", "
slaves += slave.name
s.item("notify-out", slaves)
if slaves:
s.item("notify", "[%s]" % slaves)
s.item("xfr-out", "local, test")
if z.ddns:
s.item("update-in", "test")
if acl:
acl += ", "
acl += "acl_local, acl_test"
s.item("acl", "[%s]" % acl)
if z.ixfr and not z.master:
s.item("ixfr-from-differences", "on")
s.item_str("ixfr-from-differences", "on")
if len(z.query_modules) > 0:
s.begin("query_module")
for query_module in z.query_modules:
s.item(query_module[0], '"' + query_module[1] + '"')
s.item_str(query_module[0], '"' + query_module[1] + '"')
s.end()
s.end()
s.end()
s.begin("log")
s.begin("stdout")
s.item("any", "debug")
s.end()
s.begin("stderr")
s.end()
s.begin("syslog")
s.end()
s.id_item("to", "stdout")
s.item_str("any", "debug")
s.end()
self.start_params = ["-c", self.confile]

View file

@ -10,15 +10,14 @@ AM_LDFLAGS = \
LDADD = \
$(top_builddir)/libtap/libtap.a \
$(top_builddir)/src/libknot-int.la \
$(top_builddir)/src/libknot-yparser.la \
$(top_builddir)/src/libknotd.la
$(top_builddir)/src/libknotd.la \
$(top_builddir)/src/libknot-yparser.la
check_PROGRAMS = \
acl \
base32hex \
base64 \
changeset \
changeset \
descriptor \
dname \
dthreads \

View file

@ -14,6 +14,7 @@
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <assert.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <tap/basic.h>
@ -23,127 +24,78 @@
#include "knot/updates/acl.h"
#include "knot/conf/conf.h"
static int acl_insert(list_t *acl, const struct sockaddr_storage *addr,
uint8_t prefix, knot_tsig_key_t *key)
{
assert(acl);
assert(addr);
conf_iface_t *iface = malloc(sizeof(conf_iface_t));
assert(iface);
conf_remote_t *remote = malloc(sizeof(conf_remote_t));
assert(remote);
remote->remote = iface;
memset(iface, 0, sizeof(conf_iface_t));
iface->prefix = prefix;
iface->key = key;
memcpy(&iface->addr, addr, sizeof(struct sockaddr_storage));
add_tail(acl, &remote->n);
return KNOT_EOK;
}
int main(int argc, char *argv[])
{
plan(15);
plan_lazy();
conf_iface_t *match = NULL;
list_t acl;
init_list(&acl);
int ret;
struct sockaddr_storage t;
// Create IPv4 address
struct sockaddr_storage test_v4;
int ret = sockaddr_set(&test_v4, AF_INET, "127.0.0.1", 12345);
ok(ret == KNOT_EOK, "acl: new IPv4 address");
// 127 dec ~ 01111111 bin
// 170 dec ~ 10101010 bin
struct sockaddr_storage ref4;
assert(sockaddr_set(&ref4, AF_INET, "127.170.170.127", 0) == KNOT_EOK);
// Create IPv6 address
struct sockaddr_storage test_v6;
ret = sockaddr_set(&test_v6, AF_INET6, "::1", 54321);
ok(ret == KNOT_EOK, "acl: new IPv6 address");
// 7F hex ~ 01111111 bin
// AA hex ~ 10101010 bin
struct sockaddr_storage ref6;
assert(sockaddr_set(&ref6, AF_INET6, "7FAA::AA7F", 0) == KNOT_EOK);
// Create simple IPv4 rule
ret = acl_insert(&acl, &test_v4, IPV4_PREFIXLEN, NULL);
ok(ret == KNOT_EOK, "acl: inserted IPv4 rule");
ret = netblock_match(&ref4, &ref6, 32);
ok(ret == false, "match: family mismatch");
// Create simple IPv6 rule
ret = acl_insert(&acl, &test_v6, IPV6_PREFIXLEN, NULL);
ok(ret == KNOT_EOK, "acl: inserted IPv6 rule");
ret = netblock_match(NULL, &ref4, 32);
ok(ret == false, "match: NULL first parameter");
ret = netblock_match(&ref4, NULL, 32);
ok(ret == false, "match: NULL second parameter");
// Attempt to match unmatching address
struct sockaddr_storage unmatch_v4;
sockaddr_set(&unmatch_v4, AF_INET, "10.10.10.10", 24424);
match = acl_find(&acl, &unmatch_v4, NULL);
ok(match == NULL, "acl: matching non-existing address");
ret = netblock_match(&ref4, &ref4, 31);
ok(ret == true, "match: ipv4 - identity, subnet");
ret = netblock_match(&ref4, &ref4, 32);
ok(ret == true, "match: ipv4 - identity, full prefix");
ret = netblock_match(&ref4, &ref4, 33);
ok(ret == true, "match: ipv4 - identity, prefix overflow");
// Attempt to match unmatching IPv6 address
struct sockaddr_storage unmatch_v6;
sockaddr_set(&unmatch_v6, AF_INET6, "2001:db8::1428:57ab", 24424);
match = acl_find(&acl, &unmatch_v6, NULL);
ok(match == NULL, "acl: matching non-existing IPv6 address");
ret = netblock_match(&ref6, &ref6, 127);
ok(ret == true, "match: ipv6 - identity, subnet");
ret = netblock_match(&ref6, &ref6, 128);
ok(ret == true, "match: ipv6 - identity, full prefix");
ret = netblock_match(&ref6, &ref6, 129);
ok(ret == true, "match: ipv6 - identity, prefix overflow");
// Attempt to match matching address
match = acl_find(&acl, &test_v4, NULL);
ok(match != NULL, "acl: matching existing address");
// 124 dec ~ 01111100 bin
assert(sockaddr_set(&t, AF_INET, "124.0.0.0", 0) == KNOT_EOK);
ret = netblock_match(&t, &ref4, 5);
ok(ret == true, "match: ipv4 - first byte, shorter prefix");
ret = netblock_match(&t, &ref4, 6);
ok(ret == true, "match: ipv4 - first byte, precise prefix");
ret = netblock_match(&t, &ref4, 7);
ok(ret == false, "match: ipv4 - first byte, not match");
// Attempt to match matching address
match = acl_find(&acl, &test_v6, NULL);
ok(match != NULL, "acl: matching existing IPv6 address");
assert(sockaddr_set(&t, AF_INET, "127.170.170.124", 0) == KNOT_EOK);
ret = netblock_match(&t, &ref4, 29);
ok(ret == true, "match: ipv4 - last byte, shorter prefix");
ret = netblock_match(&t, &ref4, 30);
ok(ret == true, "match: ipv4 - last byte, precise prefix");
ret = netblock_match(&t, &ref4, 31);
ok(ret == false, "match: ipv4 - last byte, not match");
// Attempt to match subnet
struct sockaddr_storage match_pf4, test_pf4;
sockaddr_set(&match_pf4, AF_INET, "192.168.1.0", 0);
acl_insert(&acl, &match_pf4, 24, NULL);
sockaddr_set(&test_pf4, AF_INET, "192.168.1.20", 0);
match = acl_find(&acl, &test_pf4, NULL);
ok(match != NULL, "acl: searching address in matching prefix /24");
// 7C hex ~ 01111100 bin
assert(sockaddr_set(&t, AF_INET6, "7CAA::", 0) == KNOT_EOK);
ret = netblock_match(&t, &ref6, 5);
ok(ret == true, "match: ipv6 - first byte, shorter prefix");
ret = netblock_match(&t, &ref6, 6);
ok(ret == true, "match: ipv6 - first byte, precise prefix");
ret = netblock_match(&t, &ref6, 7);
ok(ret == false, "match: ipv6 - first byte, not match");
// Attempt to search non-matching subnet
sockaddr_set(&test_pf4, AF_INET, "192.168.2.20", 0);
match = acl_find(&acl, &test_pf4, NULL);
ok(match == NULL, "acl: searching address in non-matching prefix /24");
assert(sockaddr_set(&t, AF_INET6, "7FAA::AA7C", 0) == KNOT_EOK);
ret = netblock_match(&t, &ref6, 125);
ok(ret == true, "match: ipv6 - last byte, shorter prefix");
ret = netblock_match(&t, &ref6, 126);
ok(ret == true, "match: ipv6 - last byte, precise prefix");
ret = netblock_match(&t, &ref6, 127);
ok(ret == false, "match: ipv6 - last byte, not match");
// Attempt to match v6 subnet
struct sockaddr_storage match_pf6, test_pf6;
sockaddr_set(&match_pf6, AF_INET6, "2001:0DB8:0400:000e:0:0:0:AB00", 0);
acl_insert(&acl, &match_pf6, 120, NULL);
sockaddr_set(&test_pf6, AF_INET6, "2001:0DB8:0400:000e:0:0:0:AB03", 0);
match = acl_find(&acl, &test_pf6, NULL);
ok(match != NULL, "acl: searching v6 address in matching prefix /120");
// Attempt to search non-matching subnet
sockaddr_set(&test_pf6, AF_INET6, "2001:0DB8:0400:000e:0:0:0:CCCC", 0);
match = acl_find(&acl, &test_pf6, NULL);
ok(match == NULL, "acl: searching v6 address in non-matching prefix /120");
// Attempt to search subnet with key (multiple keys)
knot_tsig_key_t key_a, key_b;
knot_tsig_create_key("tsig-key1", DNSSEC_TSIG_HMAC_MD5, "Wg==", &key_a);
knot_tsig_create_key("tsig-key2", DNSSEC_TSIG_HMAC_MD5, "Wg==", &key_b);
acl_insert(&acl, &match_pf6, 120, &key_a);
acl_insert(&acl, &match_pf6, 120, &key_b);
sockaddr_set(&test_pf6, AF_INET6, "2001:0DB8:0400:000e:0:0:0:AB03", 0);
match = acl_find(&acl, &test_pf6, key_a.name);
ok(match != NULL && match->key == &key_a, "acl: searching v6 address with TSIG key A");
match = acl_find(&acl, &test_pf6, key_b.name);
ok(match != NULL && match->key == &key_b, "acl: searching v6 address with TSIG key B");
// Attempt to search subnet with mismatching key
knot_tsig_key_t badkey;
knot_tsig_create_key("tsig-bad", DNSSEC_TSIG_HMAC_MD5, "Wg==", &badkey);
match = acl_find(&acl, &test_pf6, badkey.name);
ok(match == NULL, "acl: searching v6 address with bad TSIG key");
knot_tsig_key_free(&badkey);
knot_tsig_key_free(&key_a);
knot_tsig_key_free(&key_b);
conf_remote_t *remote = NULL, *next = NULL;
WALK_LIST_DELSAFE(remote, next, acl) {
free(remote->remote);
free(remote);
}
// Return
return 0;
}

View file

@ -14,7 +14,7 @@ static inline void create_root_zone(server_t *server, mm_ctx_t *mm)
/* SOA RDATA. */
#define SOA_RDLEN 30
static const uint8_t SOA_RDATA[SOA_RDLEN] = {
0x02, 0x6e, 0x73, 0x00, /* ns. */
0x02, 'n', 's', 0x00, /* ns. */
0x04, 'm', 'a', 'i', 'l', 0x00,/* mail. */
0x77, 0xdf, 0x1e, 0x63, /* serial */
0x00, 0x01, 0x51, 0x80, /* refresh */
@ -24,11 +24,7 @@ static inline void create_root_zone(server_t *server, mm_ctx_t *mm)
};
/* Insert root zone. */
conf_zone_t *conf = malloc(sizeof(conf_zone_t));
conf_init_zone(conf);
conf->name = strdup(".");
zone_t *root = zone_new(conf);
zone_t *root = zone_new(ROOT_DNAME);
root->contents = zone_contents_new(root->name);
knot_rrset_t *soa = knot_rrset_new(root->name, KNOT_RRTYPE_SOA, KNOT_CLASS_IN, mm);
@ -57,9 +53,23 @@ static inline int create_fake_server(server_t *server, mm_ctx_t *mm)
}
/* Create configuration. */
s_config = conf_new(strdup("rc:/noconf"));
conf()->identity = strdup("bogus.ns");
conf()->version = strdup("0.11");
const char *conf_str = "server:\n identity: bogus.ns\n version: 0.11\n";
conf_t *conf;
ret = conf_new(&conf, conf_scheme, NULL);
if (ret != KNOT_EOK) {
return ret;
}
ret = conf_import(conf, conf_str, false);
if (ret != KNOT_EOK) {
conf_free(conf, false);
return ret;
}
ret = conf_post_open(conf);
if (ret != KNOT_EOK) {
conf_free(conf, false);
return ret;
}
conf_update(conf);
/* Insert root zone. */
create_root_zone(server, mm);

View file

@ -213,8 +213,7 @@ static void test_store_load(const char *jfilename)
uint8_t *apex = (uint8_t *)"\4test";
/* Create fake zone. */
conf_zone_t zconf = { .ixfr_db = (char *)jfilename, .ixfr_fslimit = filesize };
zone_t z = { .name = apex, .conf = &zconf };
zone_t z = { .name = apex };
/* Save and load changeset. */
changeset_t ch;
@ -223,7 +222,7 @@ static void test_store_load(const char *jfilename)
ok(ret == KNOT_EOK, "journal: store changeset");
list_t l;
init_list(&l);
ret = journal_load_changesets(&z, &l, 0, 1);
ret = journal_load_changesets(jfilename, &z, &l, 0, 1);
ok(ret == KNOT_EOK && changesets_eq(TAIL(l), &ch), "journal: load changeset");
changeset_clear(&ch);
changesets_free(&l);
@ -241,7 +240,7 @@ static void test_store_load(const char *jfilename)
/* Load all changesets stored until now. */
serial--;
ret = journal_load_changesets(&z, &l, 0, serial);
ret = journal_load_changesets(jfilename, &z, &l, 0, serial);
changesets_free(&l);
ok(ret == KNOT_EOK, "journal: load changesets");
@ -257,7 +256,7 @@ static void test_store_load(const char *jfilename)
/* Load all changesets, except the first one that got evicted. */
init_list(&l);
ret = journal_load_changesets(&z, &l, 1, serial + 1);
ret = journal_load_changesets(jfilename, &z, &l, 1, serial + 1);
changesets_free(&l);
ok(ret == KNOT_EOK, "journal: load changesets after flush");
}

View file

@ -157,7 +157,7 @@ int main(int argc, char *argv[])
/* Cleanup. */
mp_delete(mm.ctx);
server_deinit(&server);
conf_free(conf());
conf_free(conf(), false);
return 0;
}

View file

@ -184,7 +184,7 @@ int main(int argc, char *argv[])
/* Cleanup. */
mp_delete((struct mempool *)mm.ctx);
server_deinit(&server);
conf_free(conf());
conf_free(conf(), false);
return 0;
}

View file

@ -64,7 +64,7 @@ static void* responder_thread(void *arg)
#define CONNECTED_TESTS 4
#define TESTS_COUNT DISCONNECTED_TESTS + CONNECTED_TESTS
static struct knot_request *make_query(struct knot_requestor *requestor, conf_iface_t *remote)
static struct knot_request *make_query(struct knot_requestor *requestor, conf_remote_t *remote)
{
knot_pkt_t *pkt = knot_pkt_new(NULL, KNOT_WIRE_MAX_PKTSIZE, requestor->mm);
assert(pkt);
@ -75,7 +75,7 @@ static struct knot_request *make_query(struct knot_requestor *requestor, conf_i
return knot_request_make(requestor->mm, dst, src, pkt, 0);
}
static void test_disconnected(struct knot_requestor *requestor, conf_iface_t *remote)
static void test_disconnected(struct knot_requestor *requestor, conf_remote_t *remote)
{
/* Enqueue packet. */
int ret = knot_requestor_enqueue(requestor, make_query(requestor, remote));
@ -87,7 +87,7 @@ static void test_disconnected(struct knot_requestor *requestor, conf_iface_t *re
is_int(KNOT_ECONN, ret, "requestor: disconnected/wait");
}
static void test_connected(struct knot_requestor *requestor, conf_iface_t *remote)
static void test_connected(struct knot_requestor *requestor, conf_remote_t *remote)
{
/* Enqueue packet. */
int ret = knot_requestor_enqueue(requestor, make_query(requestor, remote));
@ -121,8 +121,8 @@ int main(int argc, char *argv[])
mm_ctx_t mm;
mm_ctx_mempool(&mm, MM_DEFAULT_BLKSIZE);
conf_iface_t remote;
memset(&remote, 0, sizeof(conf_iface_t));
conf_remote_t remote;
memset(&remote, 0, sizeof(conf_remote_t));
sockaddr_set(&remote.addr, AF_INET, "127.0.0.1", 0);
sockaddr_set(&remote.via, AF_INET, "127.0.0.1", 0);
@ -170,7 +170,7 @@ int main(int argc, char *argv[])
/* Cleanup. */
mp_delete((struct mempool *)mm.ctx);
server_deinit(&server);
conf_free(conf());
conf_free(conf(), false);
return 0;
}

View file

@ -23,8 +23,8 @@
#include "knot/conf/conf.h"
#include "knot/server/rrl.h"
#include "knot/zone/zone.h"
#include "knot/conf/conf.h"
#include "libknot/descriptor.h"
#include "libknot/internal/sockaddr.h"
/* Enable time-dependent tests. */
//#define ENABLE_TIMED_TESTS
@ -141,10 +141,9 @@ int main(int argc, char *argv[])
is_int(KNOT_EOK, ret, "rrl: setlocks");
/* 4. N unlimited requests. */
conf_zone_t *zone_conf = malloc(sizeof(conf_zone_t));
conf_init_zone(zone_conf);
zone_conf->name = strdup("rrl.");
zone_t *zone = zone_new(zone_conf);
knot_dname_t *zone_name = knot_dname_from_str_alloc("rrl.");
zone_t *zone = zone_new(zone_name);
knot_dname_free(&zone_name, NULL);
struct sockaddr_storage addr;
struct sockaddr_storage addr6;

View file

@ -46,10 +46,13 @@ int main(int argc, char *argv[])
const char *dbid = mkdtemp(dbid_buf);
// Mockup zones.
conf_zone_t zone_conf = { .name = "test1." };
zone_t *zone_1 = zone_new(&zone_conf);
zone_conf.name = "test2.";
zone_t *zone_2 = zone_new(&zone_conf);
knot_dname_t *zone_name;
zone_name = knot_dname_from_str_alloc("test1.");
zone_t *zone_1 = zone_new(zone_name);
knot_dname_free(&zone_name, NULL);
zone_name = knot_dname_from_str_alloc("test2.");
zone_t *zone_2 = zone_new(zone_name);
knot_dname_free(&zone_name, NULL);
assert(zone_1 && zone_2);
// Mockup zonedb.
@ -115,8 +118,6 @@ int main(int argc, char *argv[])
memcmp(timers, empty_timers, sizeof(timers)) == 0, "zone timers: sweep");
// Clean up.
zone_1->conf = NULL;
zone_2->conf = NULL;
zone_free(&zone_1);
zone_free(&zone_2);
close_timers_db(db);

View file

@ -50,11 +50,10 @@ int main(int argc, char *argv[])
/* Populate. */
for (unsigned i = 0; i < ZONE_COUNT; ++i) {
conf_zone_t *zone_conf = malloc(sizeof(conf_zone_t));
conf_init_zone(zone_conf);
zone_conf->name = strdup(zone_list[i]);
knot_dname_t *zone_name = knot_dname_from_str_alloc(zone_list[i]);
zones[i] = zone_new(zone_name);
knot_dname_free(&zone_name, NULL);
zones[i] = zone_new(zone_conf);
if (zones[i] == NULL) {
goto cleanup;
}