Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
No results found
Show changes
Commits on Source (21)
Showing
with 34923 additions and 30529 deletions
......@@ -137,6 +137,7 @@ deploy:documentation:
<<: *debian_stretch
stage: deploy
before_script:
- apt-get update
- apt-get -y install curl
only:
- tags
......
Knot DNS 2.4.1 (2017-02-10)
===========================
Improvements:
-------------
- Speed-up of rdata addition into a huge rrset
- Introduce check of minumum timeout for next refresh
- Dnsproxy module can forward all queries without local resolving
Bugfixes:
--------
- Transfer of a huge rrset goes into an infinite loop
- Huge response over TCP contains useless TC bit instead of SERVFAIL
- Failed to build utilities with disabled daemon
- Memory leaks during keys removal
- Rough TSIG packet reservation causes early truncation
- Minor out-of-bounds string termination write in rrset dump
- Server crash during stop if failed to open timers DB
- Failed to compile on OS X older than Sierra
- Poor minimum UDP-max-size configuration check
- Failed to receive one-record-per-message IXFR-style AXFR
- Kdig timeouts when receiving RCODE != NOERROR on subsequent transfer message
Knot DNS 2.4.0 (2017-01-18)
===========================
......
......@@ -4,7 +4,7 @@ AC_PREREQ([2.60])
m4_define([knot_VERSION_MAJOR],2)dnl
m4_define([knot_VERSION_MINOR],4)dnl
m4_define([knot_VERSION_PATCH],0)dnl
m4_define([knot_VERSION_PATCH],1)dnl
m4_define([knot_VERSION_EXTRA],)dnl
m4_define([knot_PKG_VERSION],[knot_VERSION_MAJOR.knot_VERSION_MINOR.knot_VERSION_PATCH]knot_VERSION_EXTRA)dnl
......@@ -486,6 +486,12 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread_np.h>]], [[cpuset_t set; CPU
AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <sched.h>]], [[cpuset_t* set = cpuset_create(); cpuset_destroy(set);]])],
[AC_DEFINE(HAVE_CPUSET_NETBSD, 1, [Define if cpuset_t and cpuset(3) exists.])])
AC_COMPILE_IFELSE(
[AC_LANG_PROGRAM([[#include <stdint.h>]],
[[uint64_t val = 0; __atomic_add_fetch(&val, 1, __ATOMIC_RELAXED);]])],
[AC_DEFINE(HAVE_ATOMIC, 1, [Define to 1 if you have '__atomic' functions.])]
)
# Prepare CFLAG_VISIBILITY to be used where needed
gl_VISIBILITY()
......
......@@ -330,7 +330,7 @@ class KnotCtl(object):
section = reply[KnotCtlDataIdx.SECTION]
item = reply[KnotCtlDataIdx.ITEM]
idx = reply[KnotCtlDataIdx.ID]
data = reply[KnotCtlDataIdx.DATA]
data = int(reply[KnotCtlDataIdx.DATA])
# Add the zone if not exists.
if zone:
......
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -139,7 +139,7 @@ static void dump_to_file(FILE *fd, server_t *server)
// Get the server identity.
conf_val_t val = conf_get(conf(), C_SRV, C_IDENT);
const char *ident = conf_str(&val);
if (val.code != KNOT_EOK || ident[0] == '\0') {
if (ident == NULL || ident[0] == '\0') {
ident = conf()->hostname;
}
......
......@@ -752,13 +752,15 @@ static int soa_query_consume(knot_layer_t *layer, knot_pkt_t *pkt)
uint32_t local_serial = knot_soa_serial(&data->soa->rrs);
uint32_t remote_serial = knot_soa_serial(&rr->rrs);
bool current = serial_is_current(local_serial, remote_serial);
bool master_uptodate = serial_is_current(remote_serial, local_serial);
REFRESH_LOG(LOG_INFO, data->zone->name, data->remote,
"remote serial %u, %s", remote_serial,
current ? "zone is up-to-date" : "zone is outdated");
current ? (master_uptodate ? "zone is up-to-date" :
"master is outdated") : "zone is outdated");
if (current) {
return KNOT_STATE_DONE;
return master_uptodate ? KNOT_STATE_DONE : KNOT_STATE_FAIL;
} else {
data->state = STATE_TRANSFER;
return KNOT_STATE_RESET;
......
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -33,7 +33,7 @@
const yp_item_t scheme_mod_dnstap[] = {
{ C_ID, YP_TSTR, YP_VNONE },
{ MOD_SINK, YP_TSTR, YP_VNONE },
{ MOD_SINK, YP_TSTR, YP_VSTR = { "" } },
{ MOD_IDENTITY, YP_TSTR, YP_VNONE },
{ MOD_VERSION, YP_TSTR, YP_VSTR = { "Knot DNS " PACKAGE_VERSION } },
{ MOD_QUERIES, YP_TBOOL, YP_VBOOL = { true } },
......@@ -46,7 +46,7 @@ int check_mod_dnstap(conf_check_t *args)
{
conf_val_t sink = conf_rawid_get_txn(args->conf, args->txn, C_MOD_DNSTAP,
MOD_SINK, args->id, args->id_len);
if (sink.code != KNOT_EOK) {
if (conf_str(&sink)[0] == '\0') {
args->err_str = "no sink specified";
return KNOT_EINVAL;
}
......@@ -235,17 +235,19 @@ int dnstap_load(struct query_module *self)
/* Set identity. */
val = conf_mod_get(self->config, MOD_IDENTITY, self->id);
if (val.code == KNOT_EOK) {
ctx->identity = strdup(conf_str(&val));
const char *ident = conf_str(&val);
ctx->identity = (ident != NULL) ? strdup(ident) : NULL;
} else {
ctx->identity = sockaddr_hostname();
ctx->identity = strdup(self->config->hostname);
}
ctx->identity_len = (ctx->identity != NULL) ? strlen(ctx->identity) : 0;
/* Set version. */
val = conf_mod_get(self->config, MOD_VERSION, self->id);
ctx->version = strdup(conf_str(&val));
ctx->version = strdup(conf_str(&val)); // Default ensures != NULL.
ctx->version_len = strlen(ctx->version);
/* Set sink. */
val = conf_mod_get(self->config, MOD_SINK, self->id);
const char *sink = conf_str(&val);
......
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -27,7 +27,7 @@
const yp_item_t scheme_mod_rosedb[] = {
{ C_ID, YP_TSTR, YP_VNONE },
{ MOD_DBDIR, YP_TSTR, YP_VNONE },
{ MOD_DBDIR, YP_TSTR, YP_VSTR = { "" } },
{ C_COMMENT, YP_TSTR, YP_VNONE },
{ NULL }
};
......@@ -36,7 +36,7 @@ int check_mod_rosedb(conf_check_t *args)
{
conf_val_t dir = conf_rawid_get_txn(args->conf, args->txn, C_MOD_ROSEDB,
MOD_DBDIR, args->id, args->id_len);
if (dir.code != KNOT_EOK) {
if (conf_str(&dir)[0] == '\0') {
args->err_str = "no database directory specified";
return KNOT_EINVAL;
}
......@@ -468,11 +468,11 @@ static int rosedb_send_log(int sock, struct sockaddr_storage *dst_addr, knot_pkt
/* Host name / Component. */
conf_val_t val = conf_get(conf(), C_SRV, C_IDENT);
if (val.code != KNOT_EOK || val.len <= 1) {
STREAM_WRITE(stream, &maxlen, snprintf, "%s ", conf()->hostname);
} else {
STREAM_WRITE(stream, &maxlen, snprintf, "%s ", conf_str(&val));
const char *ident = conf_str(&val);
if (ident == NULL || ident[0] == '\0') {
ident = conf()->hostname;
}
STREAM_WRITE(stream, &maxlen, snprintf, "%s ", ident);
STREAM_WRITE(stream, &maxlen, snprintf, "%s[%lu]: ", PACKAGE_NAME, (unsigned long) getpid());
/* Prepare log message line. */
......
......@@ -20,7 +20,6 @@
#include "knot/nameserver/chaos.h"
#include "knot/conf/conf.h"
#include "libknot/libknot.h"
#include "dnssec/lib/dnssec/random.h"
#define WISH "Knot DNS developers wish you "
#define HOPE "Knot DNS developers hope you "
......@@ -40,74 +39,61 @@ static const char *wishes[] = {
HOPE "won't find surprising news in today's journal.",
HOPE "perform rollover often just when playing roulette.",
HOPE "get notified before your domain registration expires.",
/*! \todo add more */
};
#undef WISH
#undef HOPE
/*!
* \brief Get a string result for a given TXT query.
*/
static const char *get_txt_response_string(const knot_dname_t *qname)
static const char *get_txt_response_string(knot_pkt_t *response)
{
char *qname_str = knot_dname_to_str_alloc(qname);
const char *response = NULL;
char qname[32];
if (knot_dname_to_str(qname, knot_pkt_qname(response), sizeof(qname)) == NULL) {
return NULL;
}
/* id.server and hostname.bind should have similar meaning. */
if (strcasecmp("id.server.", qname_str) == 0 ||
strcasecmp("hostname.bind.", qname_str) == 0) {
const char *response_str = NULL;
/* Allow hostname.bind. for compatibility. */
if (strcasecmp("id.server.", qname) == 0 ||
strcasecmp("hostname.bind.", qname) == 0) {
conf_val_t val = conf_get(conf(), C_SRV, C_IDENT);
response = conf_str(&val);
/* No item means auto. */
if (val.code != KNOT_EOK) {
response = conf()->hostname;
if (val.code == KNOT_EOK) {
response_str = conf_str(&val); // Can be NULL!
} else {
response_str = conf()->hostname;
}
/* Allow both version version.{server, bind}. for compatibility. */
} else if (strcasecmp("version.server.", qname_str) == 0 ||
strcasecmp("version.bind.", qname_str) == 0) {
/* Allow version.bind. for compatibility. */
} else if (strcasecmp("version.server.", qname) == 0 ||
strcasecmp("version.bind.", qname) == 0) {
conf_val_t val = conf_get(conf(), C_SRV, C_VERSION);
response = conf_str(&val);
/* No item means auto. */
if (val.code != KNOT_EOK) {
response = "Knot DNS " PACKAGE_VERSION;
if (val.code == KNOT_EOK) {
response_str = conf_str(&val); // Can be NULL!
} else {
response_str = "Knot DNS " PACKAGE_VERSION;
}
} else if (strcasecmp("fortune.", qname_str) == 0) {
} else if (strcasecmp("fortune.", qname) == 0) {
conf_val_t val = conf_get(conf(), C_SRV, C_VERSION);
/* No item means auto. */
if (val.code != KNOT_EOK) {
uint16_t wishno = dnssec_random_uint16_t() %
uint16_t wishno = knot_wire_get_id(response->wire) %
(sizeof(wishes) / sizeof(wishes[0]));
response = wishes[wishno];
response_str = wishes[wishno];
}
}
free(qname_str);
return response;
return response_str;
}
/*!
* \brief Create TXT RR with a given string content.
*
* \param owner RR owner name.
* \param response String to be saved in RDATA. Truncated to 255 chars.
* \param mm Memory context.
* \param rrset Store here.
*
* \return KNOT_EOK
*/
static int create_txt_rrset(knot_rrset_t *rrset, const knot_dname_t *owner,
const char *response, knot_mm_t *mm)
const char *response_str, knot_mm_t *mm)
{
/* Truncate response to one TXT label. */
size_t response_len = strlen(response);
if (response_len > KNOT_DNAME_MAXLEN) {
response_len = KNOT_DNAME_MAXLEN;
size_t response_len = strlen(response_str);
if (response_len > UINT8_MAX) {
response_len = UINT8_MAX;
}
knot_dname_t *rowner = knot_dname_copy(owner, mm);
if (!rowner) {
if (rowner == NULL) {
return KNOT_ENOMEM;
}
......@@ -115,7 +101,7 @@ static int create_txt_rrset(knot_rrset_t *rrset, const knot_dname_t *owner,
uint8_t rdata[response_len + 1];
rdata[0] = response_len;
memcpy(&rdata[1], response, response_len);
memcpy(&rdata[1], response_str, response_len);
int ret = knot_rrset_add_rdata(rrset, rdata, response_len + 1, 0, mm);
if (ret != KNOT_EOK) {
......@@ -126,22 +112,16 @@ static int create_txt_rrset(knot_rrset_t *rrset, const knot_dname_t *owner,
return KNOT_EOK;
}
/*!
* \brief Create a response for a TXT CHAOS query.
*
* \param return KNOT_RCODE_NOERROR if the response was successfully created,
* otherwise an RCODE representing the failure.
*/
static int answer_txt(knot_pkt_t *response)
{
const knot_dname_t *qname = knot_pkt_qname(response);
const char *response_str = get_txt_response_string(qname);
const char *response_str = get_txt_response_string(response);
if (response_str == NULL || response_str[0] == '\0') {
return KNOT_RCODE_REFUSED;
}
knot_rrset_t rrset;
int ret = create_txt_rrset(&rrset, qname, response_str, &response->mm);
int ret = create_txt_rrset(&rrset, knot_pkt_qname(response),
response_str, &response->mm);
if (ret != KNOT_EOK) {
return KNOT_RCODE_SERVFAIL;
}
......
......@@ -105,10 +105,11 @@ static int dname_cname_synth(const knot_rrset_t *dname_rr,
*/
static bool dname_cname_cannot_synth(const knot_rrset_t *rrset, const knot_dname_t *qname)
{
if (knot_dname_labels(qname, NULL)
- knot_dname_labels(rrset->owner, NULL)
+ knot_dname_labels(knot_dname_target(&rrset->rrs), NULL)
> KNOT_DNAME_MAXLABELS) {
if (knot_dname_labels(qname, NULL) - knot_dname_labels(rrset->owner, NULL) +
knot_dname_labels(knot_dname_target(&rrset->rrs), NULL) > KNOT_DNAME_MAXLABELS) {
return true;
} else if (knot_dname_size(qname) - knot_dname_size(rrset->owner) +
knot_dname_size(knot_dname_target(&rrset->rrs)) > KNOT_DNAME_MAXLEN) {
return true;
} else {
return false;
......@@ -309,20 +310,20 @@ static int follow_cname(knot_pkt_t *pkt, uint16_t rrtype, struct query_data *qda
if (rrtype == KNOT_RRTYPE_DNAME) {
if (dname_cname_cannot_synth(&cname_rr, qdata->name)) {
qdata->rcode = KNOT_RCODE_YXDOMAIN;
return ERROR;
}
knot_rrset_t dname_rr = cname_rr;
int ret = dname_cname_synth(&dname_rr, qdata->name, &cname_rr,
&pkt->mm);
if (ret != KNOT_EOK) {
qdata->rcode = KNOT_RCODE_SERVFAIL;
return ERROR;
}
ret = process_query_put_rr(pkt, qdata, &cname_rr, NULL, 0, KNOT_PF_FREE);
switch (ret) {
case KNOT_EOK: break;
case KNOT_ESPACE: return TRUNC;
default: return ERROR;
} else {
knot_rrset_t dname_rr = cname_rr;
int ret = dname_cname_synth(&dname_rr, qdata->name,
&cname_rr, &pkt->mm);
if (ret != KNOT_EOK) {
qdata->rcode = KNOT_RCODE_SERVFAIL;
return ERROR;
}
ret = process_query_put_rr(pkt, qdata, &cname_rr, NULL, 0, KNOT_PF_FREE);
switch (ret) {
case KNOT_EOK: break;
case KNOT_ESPACE: return TRUNC;
default: return ERROR;
}
}
}
......
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -410,12 +410,13 @@ static void set_rcode_to_packet(knot_pkt_t *pkt, struct query_data *qdata)
static int process_query_err(knot_layer_t *ctx, knot_pkt_t *pkt)
{
assert(pkt && ctx);
assert(ctx && pkt);
struct query_data *qdata = QUERY_DATA(ctx);
/* Initialize response from query packet. */
knot_pkt_t *query = qdata->query;
knot_pkt_init_response(pkt, query);
(void)knot_pkt_init_response(pkt, query);
knot_wire_clear_cd(pkt->wire);
/* Set TC bit if required. */
......@@ -426,31 +427,45 @@ static int process_query_err(knot_layer_t *ctx, knot_pkt_t *pkt)
/* Restore original QNAME. */
process_query_qname_case_restore(pkt, qdata);
/* Add OPT and TSIG (best effort, send reply anyway if fails). */
/* Move to Additionals to add OPT and TSIG. */
if (pkt->current != KNOT_ADDITIONAL) {
knot_pkt_begin(pkt, KNOT_ADDITIONAL);
(void)knot_pkt_begin(pkt, KNOT_ADDITIONAL);
}
/* Put OPT RR to the additional section. */
if (answer_edns_reserve(pkt, qdata) == KNOT_EOK) {
(void)answer_edns_put(pkt, qdata);
} else {
qdata->rcode = KNOT_RCODE_SERVFAIL;
if (answer_edns_reserve(pkt, qdata) != KNOT_EOK ||
answer_edns_put(pkt, qdata) != KNOT_EOK) {
qdata->rcode = KNOT_RCODE_FORMERR;
}
/* Set final RCODE to packet. */
if (qdata->rcode == KNOT_RCODE_NOERROR) {
/* Default RCODE is SERVFAIL if not otherwise specified. */
qdata->rcode = KNOT_RCODE_SERVFAIL;
}
set_rcode_to_packet(pkt, qdata);
/* Transaction security (if applicable). */
(void)process_query_sign_response(pkt, qdata);
if (process_query_sign_response(pkt, qdata) != KNOT_EOK) {
set_rcode_to_packet(pkt, qdata);
}
return KNOT_STATE_DONE;
}
/*! \brief Helper for repetitive code. */
#define PROCESS_STAGE(plan, query_stage, step, next_state, qdata) \
#define PROCESS_BEGIN(plan, step, next_state, qdata) \
if (plan != NULL) { \
WALK_LIST(step, plan->stage[query_stage]) { \
WALK_LIST(step, plan->stage[QPLAN_BEGIN]) { \
next_state = step->process(next_state, pkt, qdata, step->ctx); \
if (next_state == KNOT_STATE_FAIL) { \
goto finish; \
} \
} \
}
#define PROCESS_END(plan, step, next_state, qdata) \
if (plan != NULL) { \
WALK_LIST(step, plan->stage[QPLAN_END]) { \
next_state = step->process(next_state, pkt, qdata, step->ctx); \
if (next_state == KNOT_STATE_FAIL) { \
next_state = process_query_err(ctx, pkt); \
......@@ -490,11 +505,11 @@ static int process_query_out(knot_layer_t *ctx, knot_pkt_t *pkt)
}
/* Before query processing code. */
PROCESS_STAGE(plan, QPLAN_BEGIN, step, next_state, qdata);
PROCESS_STAGE(zone_plan, QPLAN_BEGIN, step, next_state, qdata);
PROCESS_BEGIN(plan, step, next_state, qdata);
PROCESS_BEGIN(zone_plan, step, next_state, qdata);
/* Answer based on qclass. */
if (next_state != KNOT_STATE_DONE) {
if (next_state == KNOT_STATE_PRODUCE) {
switch (knot_pkt_qclass(pkt)) {
case KNOT_CLASS_CH:
next_state = query_chaos(pkt, ctx);
......@@ -512,16 +527,17 @@ static int process_query_out(knot_layer_t *ctx, knot_pkt_t *pkt)
/* Postprocessing. */
if (next_state == KNOT_STATE_DONE || next_state == KNOT_STATE_PRODUCE) {
/* Restore original QNAME. */
process_query_qname_case_restore(pkt, qdata);
/* Move to Additionals to add OPT and TSIG. */
if (pkt->current != KNOT_ADDITIONAL) {
knot_pkt_begin(pkt, KNOT_ADDITIONAL);
(void)knot_pkt_begin(pkt, KNOT_ADDITIONAL);
}
/* Put OPT RR to the additional section. */
if (answer_edns_put(pkt, qdata) != KNOT_EOK) {
qdata->rcode = KNOT_RCODE_FORMERR;
next_state = KNOT_STATE_FAIL;
goto finish;
}
......@@ -534,23 +550,16 @@ static int process_query_out(knot_layer_t *ctx, knot_pkt_t *pkt)
}
finish:
/* Error processing. */
switch (next_state) {
case KNOT_STATE_FAIL:
/* Default RCODE is SERVFAIL if not otherwise specified. */
if (qdata->rcode == KNOT_RCODE_NOERROR) {
qdata->rcode = KNOT_RCODE_SERVFAIL;
}
next_state = process_query_err(ctx, pkt);
break;
default:
/* Store Extended RCODE - divide between header and OPT. */
if (next_state != KNOT_STATE_FAIL) {
set_rcode_to_packet(pkt, qdata);
} else {
/* Error processing. */
next_state = process_query_err(ctx, pkt);
}
/* After query processing code. */
PROCESS_STAGE(zone_plan, QPLAN_END, step, next_state, qdata);
PROCESS_STAGE(plan, QPLAN_END, step, next_state, qdata);
PROCESS_END(plan, step, next_state, qdata);
PROCESS_END(zone_plan, step, next_state, qdata);
rcu_read_unlock();
......@@ -698,7 +707,7 @@ int process_query_sign_response(knot_pkt_t *pkt, struct query_data *qdata)
}
}
return ret;
return KNOT_EOK;
/* Server failure in signing. */
fail:
......
......@@ -46,6 +46,14 @@
#include "knot/nameserver/internet.h"
#include "contrib/ucw/lists.h"
#ifdef HAVE_ATOMIC
#define ATOMIC_ADD(dst, val) __atomic_add_fetch(dst, val, __ATOMIC_RELAXED);
#define ATOMIC_SUB(dst, val) __atomic_sub_fetch(dst, val, __ATOMIC_RELAXED);
#else
#define ATOMIC_ADD(dst, val) __sync_fetch_and_add(dst, val);
#define ATOMIC_SUB(dst, val) __sync_fetch_and_sub(dst, val);
#endif
#define MODULE_ERR(mod, msg, ...) \
log_error("module '%.*s', " msg, mod[0], mod + 1, ##__VA_ARGS__)
......@@ -133,7 +141,7 @@ inline static void mod_ctr_incr(mod_ctr_t *stats, uint32_t idx, uint64_t val)
mod_ctr_t *ctr = stats + idx;
assert(ctr->count == 1);
__atomic_add_fetch(&ctr->counter, val, __ATOMIC_RELAXED);
ATOMIC_ADD(&ctr->counter, val);
}
inline static void mod_ctr_decr(mod_ctr_t *stats, uint32_t idx, uint64_t val)
......@@ -141,7 +149,7 @@ inline static void mod_ctr_decr(mod_ctr_t *stats, uint32_t idx, uint64_t val)
mod_ctr_t *ctr = stats + idx;
assert(ctr->count == 1);
__atomic_sub_fetch(&ctr->counter, val, __ATOMIC_RELAXED);
ATOMIC_SUB(&ctr->counter, val);
}
inline static void mod_ctrs_incr(mod_ctr_t *stats, uint32_t idx, uint32_t offset, uint64_t val)
......@@ -151,9 +159,9 @@ inline static void mod_ctrs_incr(mod_ctr_t *stats, uint32_t idx, uint32_t offset
// Increment the last counter if offset overflows.
if (offset < ctr->count) {
__atomic_add_fetch(&ctr->counters[offset], val, __ATOMIC_RELAXED);
ATOMIC_ADD(&ctr->counters[offset], val);
} else {
__atomic_add_fetch(&ctr->counters[ctr->count - 1], val, __ATOMIC_RELAXED);
ATOMIC_ADD(&ctr->counters[ctr->count - 1], val);
}
}
......@@ -164,9 +172,9 @@ inline static void mod_ctrs_decr(mod_ctr_t *stats, uint32_t idx, uint32_t offset
// Increment the last counter if offset overflows.
if (offset < ctr->count) {
__atomic_sub_fetch(&ctr->counters[offset], val, __ATOMIC_RELAXED);
ATOMIC_SUB(&ctr->counters[offset], val);
} else {
__atomic_sub_fetch(&ctr->counters[ctr->count - 1], val, __ATOMIC_RELAXED);
ATOMIC_SUB(&ctr->counters[ctr->count - 1], val);
}
}
......
......@@ -182,7 +182,7 @@ static int server_init_iface(iface_t *new_if, struct sockaddr_storage *addr, int
udp_bind_flags |= NET_BIND_NONLOCAL;
sock = net_bound_socket(SOCK_DGRAM, (struct sockaddr *)addr, udp_bind_flags);
if (sock >= 0 && !warn_bind) {
log_warning("address '%s' is not available", addr_str);
log_warning("address '%s' bound, but required nonlocal bind", addr_str);
warn_bind = true;
}
}
......
......@@ -320,9 +320,14 @@ int knot_pkt_init_response(knot_pkt_t *pkt, const knot_pkt_t *query)
}
pkt->size = base_size;
pkt->qname_size = query->qname_size;
memcpy(pkt->wire, query->wire, base_size);
pkt->qname_size = query->qname_size;
if (query->qname_size == 0) {
/* Reset question count if malformed. */
knot_wire_set_qdcount(pkt->wire, 0);
}
/* Update size and flags. */
knot_wire_set_qr(pkt->wire);
knot_wire_clear_tc(pkt->wire);
......
......@@ -1922,15 +1922,18 @@ static int parse_token(const char *value, kdig_params_t *params)
}
// Try to guess the meaning of the token.
if (parse_type(value, query) == KNOT_EOK) {
if (strlen(value) == 0) {
ERR("invalid empty parameter\n");
} else if (parse_type(value, query) == KNOT_EOK) {
return KNOT_EOK;
} else if (parse_class(value, query) == KNOT_EOK) {
return KNOT_EOK;
} else if (parse_name(value, &params->queries, params->config) == KNOT_EOK) {
return KNOT_EOK;
} else {
ERR("invalid parameter: %s\n", value);
}
ERR("invalid parameter: %s\n", value);
return KNOT_EINVAL;
}
......
This diff is collapsed.
This diff is collapsed.
/* Copyright (C) 2011 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -86,12 +86,12 @@ typedef struct {
/*! \brief Scanner states describing the result. */
typedef enum {
ZS_STATE_NONE, /*!< Initial state. */
ZS_STATE_NONE, /*!< Initial state (no data). */
ZS_STATE_DATA, /*!< A record parsed. */
ZS_STATE_ERROR, /*!< An error occurred. */
ZS_STATE_INCLUDE, /*!< An include directive parsed. */
ZS_STATE_INCLUDE, /*!< An include directive (see include_filename, buffer). */
ZS_STATE_EOF, /*!< The end of the current input reached. */
ZS_STATE_STOP /*!< Finished parsing. */
ZS_STATE_STOP /*!< Early stop (possibly set from a callback). */
} zs_state_t;
/*!
......@@ -134,9 +134,9 @@ struct scanner {
uint32_t item_length_position;
/*! Auxiliary pointer to item length. */
uint8_t *item_length_location;
/*! Auxiliary buffer length. */
/*! Auxiliary buffer length. Is zero if no comment after a valid record. */
uint32_t buffer_length;
/*! Auxiliary buffer for data storing. */
/*! Auxiliary buffer. Contains a comment after a valid record. */
uint8_t buffer[MAX_RDATA_LENGTH];
/*! Auxiliary buffer for current included file name. */
char include_filename[MAX_RDATA_LENGTH];
......@@ -246,7 +246,7 @@ struct scanner {
uint8_t r_data[MAX_RDATA_LENGTH];
/*
* Example: a. IN 60 MX 1 b.
* Example: a. IN 60 MX 1 b. ; A comment
*
* r_owner_length = 3
* r_owner = 016100
......@@ -255,6 +255,8 @@ struct scanner {
* r_type = 15
* r_data_length = 5
* r_data = 0001016200
* buffer_length = 11
* buffer = " A comment"
*/
};
......
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -334,9 +334,6 @@ static void parse(
// Initialization of the last r_data byte.
uint8_t *rdata_stop = s->r_data + MAX_RDATA_LENGTH - 1;
// External processing interrupt indicator.
bool escape = false;
// Write scanner body (in C).
%% write exec;
......@@ -391,39 +388,45 @@ int zs_parse_record(
return -1;
}
// Stop parsing if stop or after the final parsing.
if (s->state == ZS_STATE_STOP || s->input.eof) {
return -1;
// Check if parsing is possible.
switch (s->state) {
case ZS_STATE_NONE:
case ZS_STATE_DATA:
case ZS_STATE_INCLUDE:
break;
case ZS_STATE_ERROR:
if (s->error.fatal) {
return -1;
}
break;
default:
// Return if stop or end of file.
return 0;
}
// Check for the end of the input.
if (s->input.current != s->input.end) {
// Try to parse another item.
s->state = ZS_STATE_NONE;
// Parse the next item.
parse(s);
return 0;
}
switch (s->state) {
case ZS_STATE_NONE:
// Indicate end of the input.
s->state = ZS_STATE_EOF;
return 0;
case ZS_STATE_EOF:
// Parse the final block.
if (zs_set_input_string(s, "\n", 1) != 0) {
return -1;
}
s->input.eof = true;
parse(s);
if (s->state == ZS_STATE_EOF) {
return -1;
// Finish if nothing was parsed.
if (s->state == ZS_STATE_NONE) {
// Parse the final block.
if (zs_set_input_string(s, "\n", 1) != 0) {
return -1;
}
s->input.eof = true;
parse(s);
if (s->state == ZS_STATE_NONE) {
s->state = ZS_STATE_EOF;
}
}
return 0;
default:
return -1;;
} else {
s->state = ZS_STATE_EOF;
}
return 0;
}
__attribute__((visibility("default")))
......@@ -439,8 +442,8 @@ int zs_parse_all(
// Parse input block.
parse(s);
// Parse trailing newline-char block if not stop.
if (s->state != ZS_STATE_STOP) {
// Parse trailing newline-char block if it makes sense.
if (s->state != ZS_STATE_STOP && !s->error.fatal) {
if (zs_set_input_string(s, "\n", 1) != 0) {
return -1;
}
......@@ -448,7 +451,7 @@ int zs_parse_all(
parse(s);
}
// Check if any errors has occurred.
// Check if any errors have occurred.
if (s->error.counter > 0) {
return -1;
}
......
/* Copyright (C) 2016 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
/* Copyright (C) 2017 CZ.NIC, z.s.p.o. <knot-dns@labs.nic.cz>
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
......@@ -41,13 +41,26 @@
s->multiline = false;
}
action _comment {
if (s->buffer_length < sizeof(s->buffer) - 1) {
s->buffer[s->buffer_length++] = fc;
}
}
action _comment_exit {
s->buffer[s->buffer_length++] = 0;
}
action _rest_init {
s->buffer[0] = 0;
s->buffer_length = 0;
}
action _rest_error {
WARN(ZS_BAD_REST);
fhold; fgoto err_line;
}
newline = '\n' $_newline;
comment = ';' . (^newline)*;
comment = (';' . (^newline)* $_comment) %_comment_exit;
# White space separation. With respect to parentheses and included comments.
sep = ( [ \t] # Blank characters.
......@@ -56,7 +69,7 @@
| ')' $_check_multiline_end # End of multiline.
)+; # Apply more times.
rest = (sep? :> comment?) $!_rest_error; # Useless text after record.
rest = (sep? :> comment?) >_rest_init $!_rest_error; # Comments.
# Artificial machines which are used for next state transition only!
all_wchar = [ \t\n;()];
......@@ -96,33 +109,26 @@
if (s->process.error != NULL) {
s->process.error(s);
// Stop the scanner if required.
// Stop if required from the callback.
if (s->state == ZS_STATE_STOP) {
fbreak;
}
}
// Stop the scanner if fatal.
// Stop the scanner if fatal error.
if (s->error.fatal) {
s->state = ZS_STATE_STOP;
fbreak;
}
fgoto main;
} else {
// Return if external processing.
escape = true;
}
}
action _err_line_exit_final {
if (escape) {
fnext main; fbreak;
} else {
fgoto main;
fhold; fnext main; fbreak;
}
}
# Fill rest of the line to buffer and skip to main loop.
err_line := (^newline $_err_line)* >_err_line_init
%_err_line_exit . newline @_err_line_exit_final;
%_err_line_exit . newline;
# END
# BEGIN - Domain name labels processing
......@@ -730,10 +736,7 @@
}
// Let the caller to solve the include.
if (!s->process.automatic) {
s->state = ZS_STATE_INCLUDE;
escape = true;
} else {
if (s->process.automatic) {
// Create new scanner for included zone file.
zs_scanner_t *ss = malloc(sizeof(zs_scanner_t));
if (ss == NULL) {
......@@ -750,6 +753,7 @@
zs_parse_all(ss) != 0) {
// File internal errors are handled by error callback.
if (ss->error.counter > 0) {
s->error.counter += ss->error.counter;
ERR(ZS_UNPROCESSED_INCLUDE);
// General include file error.
} else {
......@@ -761,6 +765,9 @@
}
zs_deinit(ss);
free(ss);
} else {
s->state = ZS_STATE_INCLUDE;
fhold; fnext main; fbreak;
}
}
......@@ -783,9 +790,6 @@
# Remove stop processing flag.
action _directive_exit {
NOERR;
if (escape) {
fnext main; fbreak;
}
}
action _directive_error {
ERR(ZS_BAD_DIRECTIVE);
......@@ -2031,7 +2035,7 @@
if (s->process.record != NULL) {
s->process.record(s);
// Stop the scanner if required.
// Stop if required from the callback.
if (s->state == ZS_STATE_STOP) {
fbreak;
}
......