Commit 6489550a authored by Marek Vavruša's avatar Marek Vavruša

Merge branch 'master' into new_node

Conflicts:
	src/knot/dnssec/zone-sign.c
	src/knot/updates/ddns.c
	src/knot/updates/xfr-in.c
	src/knot/zone/node.c
	src/knot/zone/node.h
	src/knot/zone/semantic-check.c
	src/knot/zone/zone-contents.c
	src/knot/zone/zone-contents.h
	src/knot/zone/zone-create.c
	src/libknot/rrset.c
	tests-extra/tests/ddns/basic/test.py

Note: ddns/basic fails now, but I don't think it's caused by my merge
jutsu.
parents c3535865 cca75f15
language: c
compiler:
- gcc
before_install:
- sudo apt-get update -qq
- sudo apt-get install -qq autotools-dev autoconf automake libtool libssl-dev liburcu-dev flex bison ragel pkg-config texinfo texlive lcov
- sudo pip install cpp-coveralls --use-mirrors
before_script:
- autoreconf -fi
script:
- ./configure --enable-code-coverage && make && make -k check
after_success:
- coveralls --exclude zscanner/ --exclude tests/ --exclude src/cf-lex.l --exclude src/cf-parse.y --exclude src/scanner_body.rl --exclude src/scanner.c --exclude src/functions.c --exclude src/loader.c --exclude src/error.c --exclude src/scanner.rl --exclude src/allocator.h --build-root ./src/
/* Coverity Scan model
*
* This is a modeling file for Coverity Scan. Modeling helps to avoid false
* positives.
*
* - A model file can't import any header files.
* - Therefore only some built-in primitives like int, char and void are
* available but not wchar_t, NULL etc.
* - Modeling doesn't need full structs and typedefs. Rudimentary structs
* and similar types are sufficient.
* - An uninitialized local pointer is not an error. It signifies that the
* variable could be either NULL or have some data.
*
* Coverity Scan doesn't pick up modifications automatically. The model file
* must be uploaded by an admin in the analysis settings of
* http://scan.coverity.com/projects/200
*/
/* empty modeling file for now */
......@@ -35,7 +35,7 @@ const error_table_t knot_error_msgs[] = {
{ KNOT_ECONNREFUSED, "Connection refused." },
{ KNOT_EISCONN, "Already connected." },
{ KNOT_EADDRINUSE, "Address already in use." },
{ KNOT_ENOENT, "Resource not found." },
{ KNOT_ENOENT, "Not exists." },
{ KNOT_ERANGE, "Value is out of range." },
/* General errors. */
......@@ -61,6 +61,7 @@ const error_table_t knot_error_msgs[] = {
{ KNOT_EPAYLOAD, "Payload in OPT RR larger than max wire size." },
{ KNOT_ECRC, "CRC check failed." },
{ KNOT_EPREREQ, "UPDATE prerequisity not met." },
{ KNOT_ETTL, "TTL mismatch." },
{ KNOT_ENOXFR, "Transfer was not sent." },
{ KNOT_ENOIXFR, "Transfer is not IXFR (is in AXFR format)." },
{ KNOT_EXFRREFUSED, "Zone transfer refused by the server." },
......
......@@ -81,6 +81,7 @@ enum knot_error {
KNOT_EPAYLOAD, /*!< Payload in OPT RR larger than max wire size. */
KNOT_ECRC, /*!< Wrong dump CRC. */
KNOT_EPREREQ, /*!< UPDATE prerequisity not met. */
KNOT_ETTL, /*!< TTL mismatch. */
KNOT_ENOXFR, /*!< Transfer was not sent. */
KNOT_ENOIXFR, /*!< Transfer is not IXFR (is in AXFR format). */
KNOT_EXFRREFUSED, /*!< Zone transfer refused by the server. */
......
......@@ -76,6 +76,16 @@ static void conf_init_iface(void *scanner, char* ifname)
this_iface->name = ifname;
}
static void conf_set_iface(void *scanner, struct sockaddr_storage *ss, int family, char* addr, int port)
{
int ret = sockaddr_set(ss, family, addr, port);
if (ret != KNOT_EOK) {
cf_error(scanner, "invalid address for '%s': %s@%d\n",
this_iface->name, addr, port);
}
free(addr);
}
static void conf_start_iface(void *scanner, char* ifname)
{
conf_init_iface(scanner, ifname);
......@@ -525,20 +535,16 @@ interface:
}
}
| interface ADDRESS IPA ';' {
sockaddr_set(&this_iface->addr, AF_INET, $3.t, CONFIG_DEFAULT_PORT);
free($3.t);
conf_set_iface(scanner, &this_iface->addr, AF_INET, $3.t, CONFIG_DEFAULT_PORT);
}
| interface ADDRESS IPA '@' NUM ';' {
sockaddr_set(&this_iface->addr, AF_INET, $3.t, $5.i);
free($3.t);
conf_set_iface(scanner, &this_iface->addr, AF_INET, $3.t, $5.i);
}
| interface ADDRESS IPA6 ';' {
sockaddr_set(&this_iface->addr, AF_INET6, $3.t, CONFIG_DEFAULT_PORT);
free($3.t);
conf_set_iface(scanner, &this_iface->addr, AF_INET6, $3.t, CONFIG_DEFAULT_PORT);
}
| interface ADDRESS IPA6 '@' NUM ';' {
sockaddr_set(&this_iface->addr, AF_INET, $3.t, $5.i);
free($3.t);
conf_set_iface(scanner, &this_iface->addr, AF_INET6, $3.t, $5.i);
}
;
......@@ -701,34 +707,28 @@ remote:
}
}
| remote ADDRESS IPA ';' {
sockaddr_set(&this_remote->addr, AF_INET, $3.t, CONFIG_DEFAULT_PORT);
conf_set_iface(scanner, &this_remote->addr, AF_INET, $3.t, CONFIG_DEFAULT_PORT);
this_remote->prefix = IPV4_PREFIXLEN;
free($3.t);
}
| remote ADDRESS IPA '/' NUM ';' {
sockaddr_set(&this_remote->addr, AF_INET, $3.t, 0);
conf_set_iface(scanner, &this_remote->addr, AF_INET, $3.t, 0);
SET_NUM(this_remote->prefix, $5.i, 0, IPV4_PREFIXLEN, "prefix length");
free($3.t);
}
| remote ADDRESS IPA '@' NUM ';' {
sockaddr_set(&this_remote->addr, AF_INET, $3.t, $5.i);
conf_set_iface(scanner, &this_remote->addr, AF_INET, $3.t, $5.i);
this_remote->prefix = IPV4_PREFIXLEN;
free($3.t);
}
| remote ADDRESS IPA6 ';' {
sockaddr_set(&this_remote->addr, AF_INET6, $3.t, CONFIG_DEFAULT_PORT);
conf_set_iface(scanner, &this_remote->addr, AF_INET6, $3.t, CONFIG_DEFAULT_PORT);
this_remote->prefix = IPV6_PREFIXLEN;
free($3.t);
}
| remote ADDRESS IPA6 '/' NUM ';' {
sockaddr_set(&this_remote->addr, AF_INET6, $3.t, 0);
conf_set_iface(scanner, &this_remote->addr, AF_INET6, $3.t, 0);
SET_NUM(this_remote->prefix, $5.i, 0, IPV6_PREFIXLEN, "prefix length");
free($3.t);
}
| remote ADDRESS IPA6 '@' NUM ';' {
sockaddr_set(&this_remote->addr, AF_INET6, $3.t, $5.i);
conf_set_iface(scanner, &this_remote->addr, AF_INET6, $3.t, $5.i);
this_remote->prefix = IPV6_PREFIXLEN;
free($3.t);
}
| remote KEY TEXT ';' {
if (this_remote->key != 0) {
......@@ -739,12 +739,10 @@ remote:
free($3.t);
}
| remote VIA IPA ';' {
sockaddr_set(&this_remote->via, AF_INET, $3.t, 0);
free($3.t);
conf_set_iface(scanner, &this_remote->via, AF_INET, $3.t, 0);
}
| remote VIA IPA6 ';' {
sockaddr_set(&this_remote->via, AF_INET6, $3.t, 0);
free($3.t);
conf_set_iface(scanner, &this_remote->via, AF_INET6, $3.t, 0);
}
| remote VIA TEXT ';' {
conf_remote_set_via(scanner, $3.t);
......
......@@ -817,21 +817,15 @@ const char* conf_find_default()
int conf_open(const char* path)
{
/* Check path. */
if (!path) {
return KNOT_EINVAL;
}
/* Find real path of the config file */
char *config_realpath = realpath(path, NULL);
if (config_realpath == NULL) {
return KNOT_ENOMEM;
return knot_map_errno(EINVAL, ENOENT);
}
/* Check if exists. */
struct stat st;
if (stat(config_realpath, &st) != 0) {
return KNOT_ENOENT;
/* Check if accessible. */
if (access(path, F_OK | R_OK) != 0) {
return KNOT_EACCES;
}
/* Create new config. */
......
......@@ -121,7 +121,7 @@ static int shallow_copy_signature(const knot_node_t *from, knot_node_t *to)
if (knot_rrset_empty(&from_sig)) {
return KNOT_EOK;
}
return knot_node_add_rrset(to, &from_sig);
return knot_node_add_rrset(to, &from_sig, NULL);
}
/*!
......@@ -297,7 +297,7 @@ static knot_node_t *create_nsec3_node(knot_dname_t *owner,
return NULL;
}
ret = knot_node_add_rrset(new_node, &nsec3_rrset);
ret = knot_node_add_rrset(new_node, &nsec3_rrset, NULL);
knot_rrset_clear(&nsec3_rrset, NULL);
if (ret != KNOT_EOK) {
knot_node_free(&new_node);
......
......@@ -262,40 +262,51 @@ int main(int argc, char **argv)
knot_crypto_init_threads();
atexit(knot_crypto_deinit);
/* Initialize log. */
log_init();
/* Verbose mode. */
if (verbose) {
int mask = LOG_MASK(LOG_INFO)|LOG_MASK(LOG_DEBUG);
log_levels_add(LOGT_STDOUT, LOG_ANY, mask);
}
/* Initialize pseudorandom number generator. */
srand(time(NULL));
/* POSIX 1003.1e capabilities. */
setup_capabilities();
/* Default logging to std out/err. */
log_init();
/* Open configuration. */
log_server_info("Reading configuration '%s' ...\n", config_fn);
int conf_ret = conf_open(config_fn);
int res = conf_open(config_fn);
conf_t *config = conf();
if (conf_ret != KNOT_EOK) {
if (conf_ret == KNOT_ENOENT) {
log_server_error("Couldn't open configuration file "
"'%s'.\n", config_fn);
} else {
log_server_error("Failed to load configuration '%s'.\n",
config_fn);
}
if (res != KNOT_EOK) {
log_server_fatal("Couldn't load configuration '%s': %s\n",
config_fn, knot_strerror(res));
return EXIT_FAILURE;
}
/* Initialize logging subsystem.
* @note We're logging since now. */
log_reconfigure(config, NULL);
conf_add_hook(config, CONF_LOG, log_reconfigure, NULL);
/* Initialize server. */
server_t server;
res = server_init(&server);
if (res != KNOT_EOK) {
log_server_fatal("Could not initialize server: %s\n",
knot_strerror(res));
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_server_info("Configured %zu interfaces and %zu zones.\n",
list_size(&config->ifaces), hattrie_weight(config->zones));
/* Alter privileges. */
log_update_privileges(config->uid, config->gid);
if (proc_update_privileges(config->uid, config->gid) != KNOT_EOK) {
server_deinit(&server);
log_close();
return EXIT_FAILURE;
}
......@@ -306,6 +317,8 @@ int main(int argc, char **argv)
if (daemonize) {
pidfile = pid_check_and_create();
if (pidfile == NULL) {
server_deinit(&server);
log_close();
return EXIT_FAILURE;
}
......@@ -329,28 +342,6 @@ int main(int argc, char **argv)
/* Now we're going multithreaded. */
rcu_register_thread();
/* Initialize configuration hooks. */
log_reconfigure(config, NULL);
conf_add_hook(config, CONF_LOG, log_reconfigure, NULL);
/* Initialize server. */
server_t server;
int res = server_init(&server);
if (res != KNOT_EOK) {
log_server_fatal("Could not initialize server: %s\n",
knot_strerror(res));
rcu_unregister_thread();
pid_cleanup(pidfile);
log_close();
return EXIT_FAILURE;
}
/* Reconfigure server interfaces. */
server_reconfigure(config, &server);
conf_add_hook(config, CONF_ALL, server_reconfigure, &server);
log_server_info("Configured %zu interfaces and %zu zones.\n",
list_size(&config->ifaces), hattrie_weight(config->zones));
/* Populate zone database and add reconfiguration hook. */
log_server_info("Loading zones...\n");
server_update_zones(config, &server);
......
......@@ -22,7 +22,7 @@
#include "common/lists.h"
#include "knot/server/zones.h"
/* AXFR context. */
/* AXFR context. @note aliasing the generic xfr_proc */
struct axfr_proc {
struct xfr_proc proc;
hattrie_iter_t *i;
......@@ -85,10 +85,10 @@ static int axfr_process_node_tree(knot_pkt_t *pkt, const void *item, struct xfr_
static void axfr_answer_cleanup(struct query_data *qdata)
{
struct xfr_proc *axfr = (struct xfr_proc *)qdata->ext;
struct axfr_proc *axfr = (struct axfr_proc *)qdata->ext;
mm_ctx_t *mm = qdata->mm;
ptrlist_free(&axfr->nodes, mm);
ptrlist_free(&axfr->proc.nodes, mm);
mm->free(axfr);
/* Allow zone changes (finished). */
......@@ -102,23 +102,23 @@ static int axfr_answer_init(struct query_data *qdata)
/* Create transfer processing context. */
mm_ctx_t *mm = qdata->mm;
knot_zone_contents_t *zone = qdata->zone->contents;
struct xfr_proc *xfer = mm->alloc(mm->ctx, sizeof(struct axfr_proc));
if (xfer == NULL) {
struct axfr_proc *axfr = mm->alloc(mm->ctx, sizeof(struct axfr_proc));
if (axfr == NULL) {
return KNOT_ENOMEM;
}
memset(xfer, 0, sizeof(struct axfr_proc));
init_list(&xfer->nodes);
memset(axfr, 0, sizeof(struct axfr_proc));
init_list(&axfr->proc.nodes);
/* Put data to process. */
gettimeofday(&xfer->tstamp, NULL);
ptrlist_add(&xfer->nodes, zone->nodes, mm);
gettimeofday(&axfr->proc.tstamp, NULL);
ptrlist_add(&axfr->proc.nodes, zone->nodes, mm);
/* Put NSEC3 data if exists. */
if (!knot_zone_tree_is_empty(zone->nsec3_nodes)) {
ptrlist_add(&xfer->nodes, zone->nsec3_nodes, mm);
ptrlist_add(&axfr->proc.nodes, zone->nsec3_nodes, mm);
}
/* Set up cleanup callback. */
qdata->ext = xfer;
qdata->ext = axfr;
qdata->ext_cleanup = &axfr_answer_cleanup;
/* No zone changes during multipacket answer (unlocked in axfr_answer_cleanup) */
......@@ -208,7 +208,7 @@ int axfr_answer(knot_pkt_t *pkt, struct query_data *qdata)
knot_pkt_reserve(pkt, tsig_wire_maxsize(qdata->sign.tsig_key));
/* Answer current packet (or continue). */
struct xfr_proc *xfer = qdata->ext;
struct axfr_proc *axfr = (struct axfr_proc *)qdata->ext;
ret = xfr_process_list(pkt, &axfr_process_node_tree, qdata);
switch(ret) {
case KNOT_ESPACE: /* Couldn't write more, send packet and continue. */
......@@ -216,8 +216,8 @@ int axfr_answer(knot_pkt_t *pkt, struct query_data *qdata)
case KNOT_EOK: /* Last response. */
gettimeofday(&now, NULL);
AXFR_LOG(LOG_INFO, "Finished in %.02fs (%u messages, ~%.01fkB).",
time_diff(&xfer->tstamp, &now) / 1000.0,
xfer->npkts, xfer->nbytes / 1024.0);
time_diff(&axfr->proc.tstamp, &now) / 1000.0,
axfr->proc.npkts, axfr->proc.nbytes / 1024.0);
return NS_PROC_DONE;
break;
default: /* Generic error. */
......
......@@ -128,6 +128,12 @@ int update_answer(knot_pkt_t *pkt, struct query_data *qdata)
return NS_PROC_FAIL;
}
/* Check if the zone is not discarded. */
if (zone->flags & ZONE_DISCARDED) {
pthread_mutex_unlock(&zone->ddns_lock);
return NS_PROC_FAIL;
}
struct timeval t_start = {0}, t_end = {0};
gettimeofday(&t_start, NULL);
UPDATE_LOG(LOG_INFO, "Started (serial %u).", knot_zone_serial(qdata->zone->contents));
......@@ -135,10 +141,22 @@ int update_answer(knot_pkt_t *pkt, struct query_data *qdata)
/* Reserve space for TSIG. */
knot_pkt_reserve(pkt, tsig_wire_maxsize(qdata->sign.tsig_key));
/* Retain zone for the whole processing so it doesn't disappear
* for example during reload.
* @note This is going to be fixed when this is made a zone event. */
zone_retain(zone);
/* Process UPDATE. */
rcu_read_unlock();
int ret = update_process(pkt, qdata);
rcu_read_lock();
/* Since we unlocked RCU read lock, it is possible that the
* zone was modified/removed in the background. Therefore,
* we must NOT touch the zone after we release it here. */
pthread_mutex_unlock(&zone->ddns_lock);
zone_release(zone);
qdata->zone = NULL;
/* Evaluate */
switch(ret) {
......@@ -288,7 +306,6 @@ static int zones_process_update_auth(struct query_data *qdata)
}
// Apply changeset to zone created by DDNS processing
if (zone_config->dnssec_enable) {
/*!
* Check if the UPDATE changed DNSKEYs. If yes, resign the whole
......@@ -391,10 +408,7 @@ static int zones_process_update_auth(struct query_data *qdata)
}
// Switch zone contents.
zone_retain(zone); /* Retain pointer for safe RCU unlock. */
rcu_read_unlock(); /* Unlock for switch. */
ret = xfrin_switch_zone(zone, new_contents, XFR_TYPE_UPDATE);
rcu_read_lock(); /* Relock */
if (ret != KNOT_EOK) {
log_zone_error("%s: Failed to replace current zone (%s)\n",
msg, knot_strerror(ret));
......@@ -404,8 +418,6 @@ static int zones_process_update_auth(struct query_data *qdata)
/* Free changesets, but not the data. */
zones_free_merged_changesets(chgsets, sec_chs);
zone_release(zone);
qdata->zone = NULL;
return KNOT_ERROR;
}
......@@ -432,12 +444,6 @@ static int zones_process_update_auth(struct query_data *qdata)
zones_schedule_zonefile_sync(zone, 0);
}
/* Since we unlocked RCU read lock, it is possible that the
* zone was modified/removed in the background. Therefore,
* we must NOT touch the zone after we release it here. */
zone_release(zone);
qdata->zone = NULL;
return ret;
}
......
......@@ -62,14 +62,6 @@ int net_unbound_socket(int type, struct sockaddr_storage *ss)
return socket;
}
/* Make the socket IPv6 only to allow 'any' for IPv4 and IPv6 at the same time. */
if (ss->ss_family == AF_INET6) {
/* Do not support mapping IPv4 in IPv6 sockets. */
int flag = 1;
(void) setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY,
&flag, sizeof(flag));
}
return socket;
}
......@@ -94,6 +86,12 @@ int net_bound_socket(int type, struct sockaddr_storage *ss)
unlink(addr_str);
}
/* Make the socket IPv6 only to allow 'any' for IPv4 and IPv6 at the same time. */
if (ss->ss_family == AF_INET6) {
(void) setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY,
&flag, sizeof(flag));
}
/* Bind to specified address. */
int ret = bind(socket, (struct sockaddr *)ss, sockaddr_len(ss));
if (ret < 0) {
......
......@@ -117,12 +117,25 @@ zone_t *load_zone_file(conf_zone_t *conf)
return NULL;
}
/* Create the new zone. */
zone_t *zone = zone_new((conf_zone_t *)conf);
if (zone == NULL) {
log_zone_error("Failed to create zone '%s': %s\n",
conf->name, knot_strerror(KNOT_ENOMEM));
return NULL;
}
struct stat st;
if (stat(conf->file, &st) < 0) {
/* Go silently and reset mtime to 0. */
memset(&st, 0, sizeof(struct stat));
}
/* 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_master(zone) == NULL);
/* Load the zone contents. */
knot_zone_contents_t *zone_contents = zonefile_load(&zl);
zonefile_close(&zl);
......@@ -130,15 +143,8 @@ zone_t *load_zone_file(conf_zone_t *conf)
/* Check the loader result. */
if (zone_contents == NULL) {
log_zone_error("Failed to load zone file '%s'.\n", conf->file);
return NULL;
}
/* Create the new zone. */
zone_t *zone = zone_new((conf_zone_t *)conf);
if (zone == NULL) {
log_zone_error("Failed to create zone '%s': %s\n",
conf->name, knot_strerror(KNOT_ENOMEM));
knot_zone_contents_deep_free(&zone_contents);
zone->conf = NULL;
zone_free(&zone);
return NULL;
}
......@@ -513,8 +519,6 @@ static int remove_old_zonedb(const knot_zonedb_t *db_new, knot_zonedb_t *db_old)
knot_zonedb_iter_next(&it);
}
synchronize_rcu();
/* Delete all deprecated zones and delete the old database. */
knot_zonedb_deep_free(&db_old);
......
......@@ -664,6 +664,15 @@ static int process_add_normal(const knot_node_t *node,
return KNOT_EOK;
}
/* First check if the TTL of the new RR is equal to that of the first
* RR in the node's RRSet. If not, refuse the UPDATE.
*/
knot_rrset_t rr_in_zone = knot_node_rrset(node, rr->type);
if (knot_node_rrtype_exists(node, rr->type) &&
knot_rrset_rr_ttl(rr, 0) != knot_rrset_rr_ttl(&rr_in_zone, 0)) {
return KNOT_ETTL;
}
const bool apex_ns = knot_node_rrtype_exists(node, KNOT_RRTYPE_SOA) &&
rr->type == KNOT_RRTYPE_NS;
return add_rr_to_chgset(rr, changeset, apex_ns ? apex_ns_rem : NULL);
......
......@@ -268,7 +268,8 @@ int xfrin_process_axfr_packet(knot_pkt_t *pkt, knot_ns_xfr_t *xfr, knot_zone_con
}
// Init zone creator
zcreator_t zc = {.z = *zone, .ret = KNOT_EOK };
zcreator_t zc = {.z = *zone,
.master = false, .ret = KNOT_EOK };
while (rr) {
if (rr->type == KNOT_RRTYPE_SOA &&
......@@ -845,10 +846,22 @@ static int add_rr(knot_node_t *node, const knot_rrset_t *rr,
}
} else {
// Inserting new RRSet, data will be copied.
int ret = knot_node_add_rrset(node, rr);
bool ttl_err = false;
int ret = knot_node_add_rrset(node, rr, &ttl_err);
if (ret != KNOT_EOK) {
return ret;
}
if (ttl_err) {
char type_str[16] = { '\0' };
knot_rrtype_to_string(rr->type, type_str, sizeof(type_str));
char *name = knot_dname_to_str(rr->owner);
char *zname = knot_dname_to_str(chset->soa_from->owner);
log_zone_warning("Changes application to zone %s: TTL mismatch"
" in %s, type %s\n", zname, name, type_str);
free(name);
free(zname);
}
}
// Get changed RRS and store for possible rollback.
......
......@@ -139,15 +139,26 @@ static int knot_node_add_rrset_no_merge(knot_node_t *node, const knot_rrset_t *r
return KNOT_EOK;
}
int knot_node_add_rrset(knot_node_t *node, const knot_rrset_t *rrset)
int knot_node_add_rrset(knot_node_t *node, const knot_rrset_t *rrset, bool *ttl_err)
{
if (node == NULL) {
if (node == NULL || rrset == NULL) {
return KNOT_EINVAL;
}
for (uint16_t i = 0; i < node->rrset_count; ++i) {
if (node->rrs[i].type == rrset->type) {
struct rr_data *node_data = &node->rrs[i];
/* Check if the added RR has the same TTL as the first
* RR in the RRSet.
*/
knot_rr_t *first = knot_rrs_rr(&node_data->rrs, 0);
uint32_t inserted_ttl = knot_rrset_rr_ttl(rrset, 0);
if (ttl_err && rrset->type != KNOT_RRTYPE_RRSIG &&
inserted_ttl != knot_rr_ttl(first)) {
*ttl_err = true;
}
return knot_rrs_merge(&node_data->rrs, &rrset->rrs, NULL);
}
}
......
......@@ -134,7 +134,7 @@ knot_node_t *knot_node_new(const knot_dname_t *owner, knot_node_t *parent,
* \retval KNOT_EOK on success.
* \retval KNOT_ERROR if the RRSet could not be inserted.
*/
int knot_node_add_rrset(knot_node_t *node, const knot_rrset_t *rrset);
int knot_node_add_rrset(knot_node_t *node, const knot_rrset_t *rrset, bool *ttl_err);
const knot_rrs_t *knot_node_rrs(const knot_node_t *node, uint16_t type);
knot_rrs_t *knot_node_get_rrs(const knot_node_t *node, uint16_t type);
......
......@@ -248,47 +248,6 @@ void err_handler_log_all(err_handler_t *handler)
}
}
/* TODO: optimize */
static bool rrset_ttls_equal(const knot_rrset_t *rrset)
{
uint16_t rr_count = knot_rrset_rr_count(rrset);
if (rr_count == 0) {
return true;
}
uint32_t prev_ttl = knot_rrset_rr_ttl(rrset, 0);
for (uint16_t i = 1; i < rr_count; ++i) {
uint32_t cur_ttl = knot_rrset_rr_ttl(rrset, i);
if (cur_ttl != prev_ttl) {
return false;
}
prev_ttl = cur_ttl;
}
return true;
}
/*!
* \brief Logs a warning if merging RRs with different TTLs.
*
* \param ttl_first TTL of the first RR in the RRSet.
* \param ttl_new TTL to be inserted.
* \param rr RRSet we're adding into.
* \param zname Zone name for logging.
*/
static void rrset_ttl_check(err_handler_t *handler,
const knot_rrset_t *rr, const knot_node_t *n)
{
if (rr->type != KNOT_RRTYPE_RRSIG && !rrset_ttls_equal(rr)) {
/* Prepare additional info string. */
char info_str[64] = { '\0' };
char type_str[16] = { '\0' };
knot_rrtype_to_string(rr->type, type_str, sizeof(type_str));
snprintf(info_str, sizeof(info_str), "Record type: %s.", type_str);
err_handler_handle_error(handler, n, ZC_ERR_TTL_MISMATCH, info_str);
}
}
/*!
* \brief Check whether DNSKEY rdata are valid.
*
......@@ -896,18 +855,6 @@ int sem_check_node_plain(const knot_zone_contents_t *zone,
}
}
int sem_check_rrset(const knot_node_t *node,
const knot_rrset_t *rrset,
err_handler_t *handler)
{
if (node == NULL || rrset == NULL || handler == NULL) {
return KNOT_EINVAL;
}
rrset_ttl_check(handler, rrset, node);
return KNOT_EOK;
}
/*!
* \brief Run semantic checks for node with DNSSEC-related types.
*
......
......@@ -224,19 +224,6 @@ int sem_check_node_plain(const knot_zone_contents_t *zone,
bool only_mandatory,
bool *fatal_error);
/*!
* \brief Checks RRSet for semantic errors. Logs errors via error handler.
*
* \param node Node containg the RRSet.
* \param rrset RRSet to be tested.
* \param handler Error handler.
*
* \return KNOT_E*
*/
int sem_check_rrset(const knot_node_t *node,
const knot_rrset_t *rrset,
err_handler_t *handler);
#endif // _KNOT_SEMANTIC_CHECK_H_
/*! @} */
......@@ -657,7 +657,7 @@ static knot_node_t *knot_zone_contents_get_nsec3_node(
static int insert_rr(knot_zone_contents_t *z,
const knot_rrset_t *rr, knot_node_t **n,
bool nsec3)
bool nsec3, bool *ttl_err)
{
if (z == NULL || knot_rrset_empty(rr) || n == NULL) {
return KNOT_EINVAL;
......@@ -687,7 +687,7 @@ static int insert_rr(knot_zone_contents_t *z,
}
}
return knot_node_add_rrset(*n, rr);
return knot_node_add_rrset(*n, rr, ttl_err);
}
static int recreate_normal_tree(const knot_zone_contents_t *z,
......@@ -795,9 +795,9 @@ static bool rrset_is_nsec3rel(const knot_rrset_t *rr)
}