mirror of
https://gitlab.nic.cz/knot/knot-dns.git
synced 2026-02-03 18:49:28 -05:00
Integrate new configuration
This commit is contained in:
parent
3542106549
commit
b533bb4057
64 changed files with 1483 additions and 1212 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 #
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
/*! @} */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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', "
|
||||
|
|
|
|||
|
|
@ -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. */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
120
src/knot/main.c
120
src/knot/main.c
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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) { \
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
/*!
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
/*! @} */
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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, ¶m);
|
||||
|
||||
tsig_init(¶m.tsig_ctx, remote->key);
|
||||
const knot_tsig_key_t *key = remote->key.name != NULL ?
|
||||
&remote->key : NULL;
|
||||
tsig_init(¶m.tsig_ctx, key);
|
||||
|
||||
ret = tsig_sign_packet(¶m.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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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" },
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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 \
|
||||
|
|
|
|||
168
tests/acl.c
168
tests/acl.c
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue