Commit 824ce5e8 authored by Daniel Salzman's avatar Daniel Salzman

Merge branch 'master' into internal_reduction

Conflicts:
	src/contrib/macros.h
	src/knot/nameserver/update.c
	src/knot/zone/events/handlers.c
	src/knot/zone/timers.c
	src/knot/zone/timers.h
	src/libknot/dname.h
	src/libknot/packet/wire.h
parents 2e0aebfc b6ba19da
......@@ -514,6 +514,7 @@ tests/conf.c
tests/conf_tools.c
tests/confdb.c
tests/confio.c
tests/db.c
tests/descriptor.c
tests/dname.c
tests/dthreads.c
......@@ -527,7 +528,6 @@ tests/internal_mem.c
tests/journal.c
tests/lookup.c
tests/modules/online_sign.c
tests/namedb.c
tests/net.c
tests/net_shortwrite.c
tests/node.c
......
......@@ -271,6 +271,12 @@ reconnect via TCP for at least some degree of service. It is worth
noting, that some responses can\(aqt be truncated (e.g. SERVFAIL).
.INDENT 0.0
.IP \(bu 2
Setting the value to \fB0\fP will cause that all rate\-limited responses will
be dropped. The outbound bandwidth and packet rate will be strictly capped
by the \fI\%rate\-limit\fP option. All legitimate requestors affected
by the limit will face denial of service and will observe excessive timeouts.
Therefore this setting is not recommended.
.IP \(bu 2
Setting the value to \fB1\fP will cause that all rate\-limited responses will
be sent as truncated. The amplification factor of the attack will be reduced,
but the outbound data bandwidth won\(aqt be lower than the incoming bandwidth.
......@@ -282,10 +288,10 @@ configuration, both outbound bandwidth and packet rate will be lower than the
inbound. On the other hand, the dropped responses enlarge the time window
for possible cache poisoning attack on the resolver.
.IP \(bu 2
Setting the value to anything larger than 2 is not advisable. Too large slip
value means more denial of service for legitimate requestors and introduces
excessive timeouts during resolution. On the contrary, a truncated answer
gives the legitimate requestor a chance to reconnect over TCP.
Setting the value to anything \fBlarger than 2\fP will keep on decreasing
the outgoing rate\-limited bandwidth, packet rate, and chances to notify
legitimate requestors to reconnect using TCP. These attributes are inversely
proportional to the configured value. Setting the value high is not advisable.
.UNINDENT
.sp
\fIDefault:\fP 1
......@@ -478,6 +484,7 @@ if a zone doesn\(aqt have another template specified.
.ft C
template:
\- id: STR
timer\-db: STR
global\-module: STR/STR ...
# All zone options (excluding \(aqtemplate\(aq item)
.ft P
......@@ -487,12 +494,20 @@ template:
.SS id
.sp
A template identifier.
.SS timer\-db
.sp
Specifies a path of the persistent timer database. The path can be specified
as a relative path to the \fIdefault\fP template \fI\%storage\fP\&.
.sp
\fICaution:\fP This option is only available in the \fIdefault\fP template.
.sp
\fIDefault:\fP \fI\%storage\fP/timers
.SS global\-module
.sp
An ordered list of references to query modules in the form
\fImodule_name/module_id\fP\&. These modules apply to all queries.
.sp
\fICaution:\fP This option is available only for the \fIdefault\fP template.
\fICaution:\fP This option is only available in the \fIdefault\fP template.
.sp
\fIDefault:\fP not set
.SH ZONE SECTION
......
......@@ -287,6 +287,12 @@ is to send each N\ :sup:`th` response as truncated, thus allowing client to
reconnect via TCP for at least some degree of service. It is worth
noting, that some responses can't be truncated (e.g. SERVFAIL).
- Setting the value to **0** will cause that all rate-limited responses will
be dropped. The outbound bandwidth and packet rate will be strictly capped
by the :ref:`server_rate-limit` option. All legitimate requestors affected
by the limit will face denial of service and will observe excessive timeouts.
Therefore this setting is not recommended.
- Setting the value to **1** will cause that all rate-limited responses will
be sent as truncated. The amplification factor of the attack will be reduced,
but the outbound data bandwidth won't be lower than the incoming bandwidth.
......@@ -298,10 +304,10 @@ noting, that some responses can't be truncated (e.g. SERVFAIL).
inbound. On the other hand, the dropped responses enlarge the time window
for possible cache poisoning attack on the resolver.
- Setting the value to anything larger than 2 is not advisable. Too large slip
value means more denial of service for legitimate requestors and introduces
excessive timeouts during resolution. On the contrary, a truncated answer
gives the legitimate requestor a chance to reconnect over TCP.
- Setting the value to anything **larger than 2** will keep on decreasing
the outgoing rate-limited bandwidth, packet rate, and chances to notify
legitimate requestors to reconnect using TCP. These attributes are inversely
proportional to the configured value. Setting the value high is not advisable.
*Default:* 1
......@@ -546,6 +552,7 @@ if a zone doesn't have another template specified.
template:
- id: STR
timer-db: STR
global-module: STR/STR ...
# All zone options (excluding 'template' item)
......@@ -556,6 +563,18 @@ id
A template identifier.
.. _template_timer-db:
timer-db
--------
Specifies a path of the persistent timer database. The path can be specified
as a relative path to the *default* template :ref:`storage<zone_storage>`.
*Caution:* This option is only available in the *default* template.
*Default:* :ref:`storage<zone_storage>`/timers
.. _template_global-module:
global-module
......@@ -564,7 +583,7 @@ global-module
An ordered list of references to query modules in the form
*module_name/module_id*. These modules apply to all queries.
*Caution:* This option is available only for the *default* template.
*Caution:* This option is only available in the *default* template.
*Default:* not set
......
......@@ -238,6 +238,10 @@ int conf_post_open(
conf->cache.srv_nsid = conf_get(conf, C_SRV, C_NSID);
conf->cache.srv_max_udp_payload = conf_get(conf, C_SRV, C_MAX_UDP_PAYLOAD);
conf->cache.srv_max_tcp_clients = conf_get(conf, C_SRV, C_MAX_TCP_CLIENTS);
conf->cache.srv_tcp_hshake_timeout = conf_get(conf, C_SRV, C_TCP_HSHAKE_TIMEOUT);
conf->cache.srv_tcp_idle_timeout = conf_get(conf, C_SRV, C_TCP_IDLE_TIMEOUT);
conf->cache.srv_tcp_reply_timeout = conf_get(conf, C_SRV, C_TCP_REPLY_TIMEOUT);
conf_activate_modules(conf, NULL, &conf->query_modules, &conf->query_plan);
......
......@@ -90,6 +90,10 @@ typedef struct {
struct {
conf_val_t srv_nsid;
conf_val_t srv_max_udp_payload;
conf_val_t srv_max_tcp_clients;
conf_val_t srv_tcp_hshake_timeout;
conf_val_t srv_tcp_idle_timeout;
conf_val_t srv_tcp_reply_timeout;
} cache;
/*! List of active query modules. */
......
......@@ -91,7 +91,7 @@ static const yp_item_t desc_server[] = {
KNOT_EDNS_MAX_UDP_PAYLOAD,
4096, YP_SSIZE } },
{ C_RATE_LIMIT, YP_TINT, YP_VINT = { 0, INT32_MAX, 0 } },
{ C_RATE_LIMIT_SLIP, YP_TINT, YP_VINT = { 1, RRL_SLIP_MAX, 1 } },
{ C_RATE_LIMIT_SLIP, YP_TINT, YP_VINT = { 0, RRL_SLIP_MAX, 1 } },
{ C_RATE_LIMIT_TBL_SIZE, YP_TINT, YP_VINT = { 1, INT32_MAX, 393241 } },
{ C_LISTEN, YP_TADDR, YP_VADDR = { 53 }, YP_FMULTI },
{ C_COMMENT, YP_TSTR, YP_VNONE },
......@@ -156,6 +156,7 @@ static const yp_item_t desc_remote[] = {
static const yp_item_t desc_template[] = {
{ C_ID, YP_TSTR, YP_VNONE },
ZONE_ITEMS
{ C_TIMER_DB, YP_TSTR, YP_VSTR = { "timers" } }, \
{ C_GLOBAL_MODULE, YP_TDATA, YP_VDATA = { 0, NULL, mod_id_to_bin, mod_id_to_txt }, \
YP_FMULTI, { check_modref } }, \
{ NULL }
......
......@@ -77,6 +77,7 @@
#define C_TCP_IDLE_TIMEOUT "\x10""tcp-idle-timeout"
#define C_TCP_REPLY_TIMEOUT "\x11""tcp-reply-timeout"
#define C_TCP_WORKERS "\x0B""tcp-workers"
#define C_TIMER_DB "\x08""timer-db"
#define C_TPL "\x08""template"
#define C_UDP_WORKERS "\x0B""udp-workers"
#define C_USER "\x04""user"
......
......@@ -295,8 +295,6 @@ int addr_range_to_txt(
int check_ref(
conf_check_t *args)
{
const char *err_str = "invalid reference";
const yp_item_t *ref = args->item->var.r.ref;
// Try to find a referenced block with the id.
......@@ -304,7 +302,8 @@ int check_ref(
int ret = conf_db_get(args->conf, args->txn, ref->name, NULL,
args->data, args->data_len, NULL);
if (ret != KNOT_EOK) {
args->err_str = err_str;
args->err_str = "invalid reference";
}
return ret;
......@@ -313,8 +312,6 @@ int check_ref(
int check_modref(
conf_check_t *args)
{
const char *err_str = "invalid module reference";
const yp_name_t *mod_name = (const yp_name_t *)args->data;
const uint8_t *id = args->data + 1 + args->data[0];
size_t id_len = args->data_len - 1 - args->data[0];
......@@ -324,7 +321,8 @@ int check_modref(
int ret = conf_db_get(args->conf, args->txn, mod_name, NULL, id, id_len,
NULL);
if (ret != KNOT_EOK) {
args->err_str = err_str;
args->err_str = "invalid module reference";
}
return ret;
......@@ -333,12 +331,10 @@ int check_modref(
int check_remote(
conf_check_t *args)
{
const char *err_str = "no remote address defined";
conf_val_t addr = conf_rawid_get_txn(args->conf, args->txn, C_RMT,
C_ADDR, args->id, args->id_len);
if (conf_val_count(&addr) == 0) {
args->err_str = err_str;
args->err_str = "no remote address defined";
return KNOT_EINVAL;
}
......@@ -348,19 +344,28 @@ int check_remote(
int check_template(
conf_check_t *args)
{
const char *err_str = "global module is only allowed with the default template";
// Ignore the default template.
if (args->id_len == CONF_DEFAULT_ID[0] &&
memcmp(args->id, CONF_DEFAULT_ID + 1, args->id_len) == 0) {
return KNOT_EOK;
}
// Check global-module.
conf_val_t g_module = conf_rawid_get_txn(args->conf, args->txn, C_TPL,
C_GLOBAL_MODULE, args->id,
args->id_len);
if (g_module.code == KNOT_EOK) {
args->err_str = err_str;
args->err_str = "global module in non-default template";
return KNOT_EINVAL;
}
// Check timer-db.
conf_val_t timer_db = conf_rawid_get_txn(args->conf, args->txn, C_TPL,
C_TIMER_DB, args->id, args->id_len);
if (timer_db.code == KNOT_EOK) {
args->err_str = "timer database location in non-default template";
return KNOT_EINVAL;
}
......@@ -370,8 +375,6 @@ int check_template(
int check_zone(
conf_check_t *args)
{
const char *err_str = "slave zone with DNSSEC signing";
conf_val_t master = conf_zone_get_txn(args->conf, args->txn,
C_MASTER, args->id);
conf_val_t dnssec = conf_zone_get_txn(args->conf, args->txn,
......@@ -379,7 +382,7 @@ int check_zone(
// DNSSEC signing is not possible with slave zone.
if (conf_val_count(&master) > 0 && conf_bool(&dnssec)) {
args->err_str = err_str;
args->err_str = "slave zone with DNSSEC signing";
return KNOT_EINVAL;
}
......
......@@ -266,8 +266,8 @@ static int cmd_remote(struct sockaddr_storage *addr, knot_tsig_key_t *key,
}
/* Default timeout. */
conf_val_t val = conf_get(conf(), C_SRV, C_TCP_REPLY_TIMEOUT);
const struct timeval tv_reply = { conf_int(&val), 0 };
conf_val_t *val = &conf()->cache.srv_tcp_reply_timeout;
const struct timeval tv_reply = { conf_int(val), 0 };
/* Connect to remote. */
char addr_str[SOCKADDR_STRLEN] = { 0 };
......
......@@ -910,8 +910,8 @@ static int remote_c_conf_unset(server_t *s, remote_cmdargs_t *a)
static int remote_senderr(int c, uint8_t *qbuf, size_t buflen)
{
rcu_read_lock();
conf_val_t val = conf_get(conf(), C_SRV, C_TCP_REPLY_TIMEOUT);
struct timeval timeout = { conf_int(&val), 0 };
conf_val_t *val = &conf()->cache.srv_tcp_reply_timeout;
struct timeval timeout = { conf_int(val), 0 };
rcu_read_unlock();
knot_wire_set_qr(qbuf);
......@@ -1052,8 +1052,8 @@ static int remote_send_chunk(int c, knot_pkt_t *query, const char *d, uint16_t l
}
rcu_read_lock();
conf_val_t val = conf_get(conf(), C_SRV, C_TCP_REPLY_TIMEOUT);
struct timeval timeout = { conf_int(&val), 0 };
conf_val_t *val = &conf()->cache.srv_tcp_reply_timeout;
struct timeval timeout = { conf_int(val), 0 };
rcu_read_unlock();
ret = net_dns_tcp_send(c, resp->wire, resp->size, &timeout);
......
......@@ -93,8 +93,8 @@ static int dnsproxy_fwd(int state, knot_pkt_t *pkt, struct query_data *qdata, vo
/* Forward request. */
ret = knot_requestor_enqueue(&re, req);
if (ret == KNOT_EOK) {
conf_val_t val = conf_get(conf(), C_SRV, C_TCP_REPLY_TIMEOUT);
struct timeval tv = { conf_int(&val), 0 };
conf_val_t *val = &conf()->cache.srv_tcp_reply_timeout;
struct timeval tv = { conf_int(val), 0 };
ret = knot_requestor_exec(&re, &tv);
} else {
knot_request_free(req, re.mm);
......
......@@ -421,7 +421,8 @@ static int ratelimit_apply(int state, knot_pkt_t *pkt, knot_layer_t *ctx)
/* Now it is slip or drop. */
conf_val_t val = conf_get(conf(), C_SRV, C_RATE_LIMIT_SLIP);
if (rrl_slip_roll(conf_int(&val))) {
int slip = conf_int(&val);
if (slip > 0 && rrl_slip_roll(slip)) {
/* Answer slips. */
if (process_query_err(ctx, pkt) != KNOT_STATE_DONE) {
return KNOT_STATE_FAIL;
......
......@@ -276,8 +276,8 @@ static int remote_forward(struct knot_request *request, conf_remote_t *remote)
/* Enqueue the request. */
ret = knot_requestor_enqueue(&re, req);
if (ret == KNOT_EOK) {
conf_val_t val = conf_get(conf(), C_SRV, C_TCP_REPLY_TIMEOUT);
struct timeval tv = { conf_int(&val), 0 };
conf_val_t *val = &conf()->cache.srv_tcp_reply_timeout;
struct timeval tv = { conf_int(val), 0 };
ret = knot_requestor_exec(&re, &tv);
} else {
knot_request_free(req, re.mm);
......@@ -378,8 +378,8 @@ static void send_update_response(const zone_t *zone, struct knot_request *req)
}
if (net_is_stream(req->fd)) {
conf_val_t val = conf_get(conf(), C_SRV, C_TCP_REPLY_TIMEOUT);
struct timeval timeout = { conf_int(&val), 0 };
conf_val_t *val = &conf()->cache.srv_tcp_reply_timeout;
struct timeval timeout = { conf_int(val), 0 };
net_dns_tcp_send(req->fd, req->resp->wire, req->resp->size,
&timeout);
} else {
......
......@@ -662,8 +662,12 @@ static void reopen_timers_database(conf_t *conf, server_t *server)
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);
val = conf_default_get(conf, C_TIMER_DB);
char *timer_db = conf_abs_path(&val, storage);
free(storage);
int ret = open_timers_db(timer_db, &server->timers_db);
free(timer_db);
if (ret != KNOT_EOK && ret != KNOT_ENOTSUP) {
log_warning("cannot open persistent timers DB (%s)",
knot_strerror(ret));
......
......@@ -113,8 +113,8 @@ static int tcp_handle(tcp_context_t *tcp, int fd,
/* Timeout. */
rcu_read_lock();
conf_val_t val = conf_get(conf(), C_SRV, C_TCP_REPLY_TIMEOUT);
struct timeval tmout = { conf_int(&val), 0 };
conf_val_t *val = &conf()->cache.srv_tcp_reply_timeout;
struct timeval tmout = { conf_int(val), 0 };
rcu_read_unlock();
/* Receive data. */
......@@ -188,8 +188,8 @@ int tcp_accept(int fd)
#ifdef SO_RCVTIMEO
struct timeval tv;
rcu_read_lock();
conf_val_t val = conf_get(conf(), C_SRV, C_TCP_IDLE_TIMEOUT);
tv.tv_sec = conf_int(&val);
conf_val_t *val = &conf()->cache.srv_tcp_idle_timeout;
tv.tv_sec = conf_int(val);
rcu_read_unlock();
tv.tv_usec = 0;
if (setsockopt(incoming, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) < 0) {
......@@ -217,8 +217,8 @@ static int tcp_event_accept(tcp_context_t *tcp, unsigned i)
/* Update watchdog timer. */
rcu_read_lock();
conf_val_t val = conf_get(conf(), C_SRV, C_TCP_HSHAKE_TIMEOUT);
fdset_set_watchdog(&tcp->set, next_id, conf_int(&val));
conf_val_t *val = &conf()->cache.srv_tcp_hshake_timeout;
fdset_set_watchdog(&tcp->set, next_id, conf_int(val));
rcu_read_unlock();
return KNOT_EOK;
......@@ -238,8 +238,8 @@ static int tcp_event_serve(tcp_context_t *tcp, unsigned i)
if (ret == KNOT_EOK) {
/* Update socket activity timer. */
rcu_read_lock();
conf_val_t val = conf_get(conf(), C_SRV, C_TCP_IDLE_TIMEOUT);
fdset_set_watchdog(&tcp->set, i, conf_int(&val));
conf_val_t *val = &conf()->cache.srv_tcp_idle_timeout;
fdset_set_watchdog(&tcp->set, i, conf_int(val));
rcu_read_unlock();
}
......@@ -258,8 +258,8 @@ static int tcp_wait_for_events(tcp_context_t *tcp)
if (!is_throttled) {
/* Configuration limit, infer maximal pool size. */
rcu_read_lock();
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);
conf_val_t *val = &conf()->cache.srv_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;
......
......@@ -25,7 +25,6 @@
#include <sys/syscall.h>
#include <string.h>
#include <assert.h>
#include <errno.h>
#include <sys/param.h>
#include <urcu.h>
#ifdef HAVE_SYS_UIO_H /* 'struct iovec' for OpenBSD */
......@@ -104,8 +103,8 @@ static inline void udp_pps_begin() {}
static inline void udp_pps_sample(unsigned n, unsigned thr_id) {}
#endif
void udp_handle(udp_context_t *udp, int fd, struct sockaddr_storage *ss,
struct iovec *rx, struct iovec *tx)
static void udp_handle(udp_context_t *udp, int fd, struct sockaddr_storage *ss,
struct iovec *rx, struct iovec *tx)
{
/* Create query processing parameter. */
struct process_query_param param = {0};
......@@ -267,7 +266,7 @@ static int (*_send_mmsg)(int, struct sockaddr *, struct mmsghdr *, size_t) = 0;
*
* Basic, sendmsg() based implementation.
*/
int udp_sendmsg(int sock, struct sockaddr *addrs, struct mmsghdr *msgs, size_t count)
static int udp_sendmsg(int sock, struct sockaddr *addrs, struct mmsghdr *msgs, size_t count)
{
int sent = 0;
for (unsigned i = 0; i < count; ++i) {
......@@ -294,7 +293,7 @@ static inline int sendmmsg(int fd, struct mmsghdr *mmsg, unsigned vlen,
*
* sendmmsg() implementation.
*/
int udp_sendmmsg(int sock, struct sockaddr *_, struct mmsghdr *msgs, size_t count)
static int udp_sendmmsg(int sock, struct sockaddr *_, struct mmsghdr *msgs, size_t count)
{
UNUSED(_);
return sendmmsg(sock, msgs, count, 0);
......
......@@ -157,8 +157,8 @@ static int zone_query_request(knot_pkt_t *query, const conf_remote_t *remote,
/* Send the queries and process responses. */
ret = knot_requestor_enqueue(&re, req);
if (ret == KNOT_EOK) {
conf_val_t val = conf_get(conf(), C_SRV, C_TCP_REPLY_TIMEOUT);
struct timeval tv = { conf_int(&val), 0 };
conf_val_t *val = &conf()->cache.srv_tcp_reply_timeout;
struct timeval tv = { conf_int(val), 0 };
ret = knot_requestor_exec(&re, &tv);
} else {
knot_request_free(req, re.mm);
......@@ -295,8 +295,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.
conf_val_t val = conf_get(conf(), C_SRV, C_TCP_REPLY_TIMEOUT);
return knot_soa_expire(soa) + 2 * conf_int(&val);
conf_val_t *val = &conf()->cache.srv_tcp_reply_timeout;
return knot_soa_expire(soa) + 2 * conf_int(val);
}
/*! \brief Schedule expire event, unless it is already scheduled. */
......
......@@ -142,28 +142,21 @@ static int read_timers(knot_db_txn_t *txn, const zone_t *zone, time_t *timers)
/* -------- API ------------------------------------------------------------- */
int open_timers_db(const char *storage, knot_db_t **db_ptr)
int open_timers_db(const char *path, knot_db_t **timer_db)
{
if (storage == NULL || db_ptr == NULL) {
if (path == NULL || timer_db == NULL) {
return KNOT_EINVAL;
}
struct knot_db_lmdb_opts opts = KNOT_DB_LMDB_OPTS_INITIALIZER;
const knot_db_api_t *db_api = knot_db_lmdb_api();
if (db_api == NULL) {
return KNOT_ENOTSUP;
}
opts.path = sprintf_alloc("%s/timers", storage);
if (opts.path == NULL) {
return KNOT_ENOMEM;
}
int ret = db_api->init(db_ptr, NULL, &opts);
free((char *)opts.path);
struct knot_db_lmdb_opts opts = KNOT_DB_LMDB_OPTS_INITIALIZER;
opts.path = path;
return ret;
return db_api->init(timer_db, NULL, &opts);
}
void close_timers_db(knot_db_t *timer_db)
......
......@@ -21,14 +21,14 @@
#include "knot/zone/zonedb.h"
/*!
* \brief Opens zone timers db. No-op without LMDB support.
* \brief Opens zone timers db.
*
* \param[in] storage Path to storage directory.
* \param[in] path Path to a directory with the database.
* \param[out] timer_db Created database.
*
* \return KNOT_E*
*/
int open_timers_db(const char *storage, knot_db_t **timer_db);
int open_timers_db(const char *path, knot_db_t **timer_db);
/*!
* \brief Closes zone timers db.
......
......@@ -28,4 +28,19 @@
#define _public_ __attribute__((visibility("default")))
#define _hidden_ __attribute__((visibility("hidden")))
/*! \brief GNU C function attributes. */
#if __GNUC__ >= 3
#define _pure_ __attribute__ ((pure))
#define _const_ __attribute__ ((const))
#define _noreturn_ __attribute__ ((noreturn))
#define _malloc_ __attribute__ ((malloc))
#define _mustcheck_ __attribute__ ((warn_unused_result))
#else
#define _pure_
#define _const_
#define _noreturn_
#define _malloc_
#define _mustcheck_
#endif
/*! @} */
......@@ -29,6 +29,7 @@
#include <stdio.h>
#include <stdbool.h>
#include "libknot/attribute.h"
#include "libknot/mm_ctx.h"
/*! \brief Type representing a domain name in wire format. */
......@@ -47,6 +48,7 @@ typedef uint8_t knot_dname_t;
* \retval KNOT_EMALF
* \retval KNOT_ESPACE
*/
_pure_ _mustcheck_
int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
const uint8_t *pkt);
......@@ -60,6 +62,7 @@ int knot_dname_wire_check(const uint8_t *name, const uint8_t *endp,
*
* \return parsed domain name or NULL.
*/
_mustcheck_
knot_dname_t *knot_dname_parse(const uint8_t *pkt, size_t *pos, size_t maxpos,
knot_mm_t *mm);
......@@ -70,6 +73,7 @@ knot_dname_t *knot_dname_parse(const uint8_t *pkt, size_t *pos, size_t maxpos,
*
* \return New domain name which is an exact copy of \a dname.
*/
_mustcheck_
knot_dname_t *knot_dname_copy(const knot_dname_t *name, knot_mm_t *mm);
/*!
......@@ -80,6 +84,7 @@ knot_dname_t *knot_dname_copy(const knot_dname_t *name, knot_mm_t *mm);
*
* \return New domain name which is an partial copy of \a dname.
*/
_mustcheck_
knot_dname_t *knot_dname_copy_part(const knot_dname_t *name, unsigned len,
knot_mm_t *mm);
......@@ -130,6 +135,7 @@ char *knot_dname_to_str(char *dst, const knot_dname_t *name, size_t maxlen);
* \brief This function is a shortcut for \ref knot_dname_to_str with
* no output buffer parameters.
*/
_mustcheck_
static inline char *knot_dname_to_str_alloc(const knot_dname_t *name)
{
return knot_dname_to_str(NULL, name, 0);
......@@ -155,6 +161,7 @@ knot_dname_t *knot_dname_from_str(uint8_t *dst, const char *name, size_t maxlen)
* \brief This function is a shortcut for \ref knot_dname_from_str with
* no output buffer parameters.
*/
_mustcheck_
static inline knot_dname_t *knot_dname_from_str_alloc(const char *name)
{
return knot_dname_from_str(NULL, name, 0);
......@@ -183,6 +190,7 @@ int knot_dname_to_lower(knot_dname_t *name);
* \retval size of the domain name.
* \retval KNOT_EINVAL
*/
_pure_
int knot_dname_size(const knot_dname_t *name);
/*!
......@@ -194,6 +202,7 @@ int knot_dname_size(const knot_dname_t *name);
* \retval size of the domain name.
* \retval KNOT_EINVAL
*/
_pure_
int knot_dname_realsize(const knot_dname_t *name, const uint8_t *pkt);
/*!
......@@ -205,6 +214,7 @@ int knot_dname_realsize(const knot_dname_t *name, const uint8_t *pkt);
* \retval true \a sub is a subdomain of \a domain.
* \retval false otherwise.
*/
_pure_
bool knot_dname_is_sub(const knot_dname_t *sub, const knot_dname_t *domain);
/*!
......@@ -216,6 +226,7 @@ bool knot_dname_is_sub(const knot_dname_t *sub, const knot_dname_t *domain);
* \retval true \a sub us a subdomain or equal to \a domain.
* \retval false otherwise.
*/
_pure_
bool knot_dname_in(const knot_dname_t *domain, const knot_dname_t *sub);
/*!
......@@ -226,6 +237,7 @@ bool knot_dname_in(const knot_dname_t *domain, const knot_dname_t *sub);
* \retval true if \a dname is a wildcard domain name.
* \retval false otherwise.
*/
_pure_
bool knot_dname_is_wildcard(const knot_dname_t *name);
/*!
......@@ -237,6 +249,7 @@ bool knot_dname_is_wildcard(const knot_dname_t *name);
*
* \return Number of labels common for the two domain names.
*/
_pure_
int knot_dname_matched_labels(const knot_dname_t *d1, const knot_dname_t *d2);
/*!
......@@ -250,6 +263,7 @@ int knot_dname_matched_labels(const knot_dname_t *d1, const knot_dname_t *d2);
* \return New domain name created by replacing suffix of \a dname of size
* \a size with \a suffix.
*/
_mustcheck_
knot_dname_t *knot_dname_replace_suffix(const knot_dname_t *name, unsigned labels,
const knot_dname_t *suffix);
......@@ -276,6 +290,7 @@ void knot_dname_free(knot_dname_t **name, knot_mm_t *mm);
* \retval > 0 if \a d1 goes after \a d2 in canonical order.
* \retval 0 if the domain names are identical.
*/
_pure_
int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2);
/*!
......@@ -295,6 +310,7 @@ int knot_dname_cmp(const knot_dname_t *d1, const knot_dname_t *d2);
* \retval 1 if d1 > d2
* \retval -1 if d1 < d2
*/
_pure_
int knot_dname_cmp_wire(const knot_dname_t *d1, const knot_dname_t *d2,
const uint8_t *pkt);
......@@ -307,6 +323,7 @@ int knot_dname_cmp_wire(const knot_dname_t *d1, const knot_dname_t *d2,
* \retval true if the domain names are identical
* \retval false if the domain names are NOT identical
*/
_pure_
bool knot_dname_is_equal(const knot_dname_t *d1, const knot_dname_t *d2);
/*!
......@@ -328,6 +345,7 @@ knot_dname_t *knot_dname_cat(knot_dname_t *d1, const knot_dname_t *d2);
*
* \retval length of the prefix
*/
_pure_
int knot_dname_prefixlen(const uint8_t *name, unsigned nlabels, const uint8_t *pkt);
/*!
......@@ -338,6 +356,7 @@ int knot_dname_prefixlen(const uint8_t *name, unsigned nlabels, const uint8_t *p
* \param name Domain name.
* \param pkt Related packet (or NULL if not compressed).
*/
_pure_
int knot_dname_labels(const uint8_t *name, const uint8_t *pkt);
/*!
......
......@@ -26,6 +26,7 @@
#include <stdint.h>
#include <stdlib.h>
#include "libknot/attribute.h"
/*! \brief Offset of DNS header fields in wireformat. */
enum knot_wire_offsets {
......@@ -897,9 +898,10 @@ uint16_t knot_wire_get_pointer(const uint8_t *pos);
static inline int knot_wire_is_pointer(const uint8_t *pos)
{
return ((pos[0] & KNOT_WIRE_PTR) == KNOT_WIRE_PTR);
return pos && ((pos[0] & KNOT_WIRE_PTR) == KNOT_WIRE_PTR);
}
_pure_ _mustcheck_
static inline const uint8_t *knot_wire_seek_label(const uint8_t *lp, const uint8_t *wire)
{
while (knot_wire_is_pointer(lp)) {
......@@ -910,8 +912,11 @@ static inline const uint8_t *knot_wire_seek_label(const uint8_t *lp, const uint8
return lp;
}
_pure_ _mustcheck_
static inline const uint8_t *knot_wire_next_label(const uint8_t *lp, const uint8_t *wire)
{
if (!lp || !lp[0]) /* No label after final label. */
return NULL;
return knot_wire_seek_label(lp + (lp[0] + sizeof(uint8_t)), wire);