summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAleš Mrázek <ales.mrazek@nic.cz>2024-07-23 19:39:45 +0200
committerAleš Mrázek <ales.mrazek@nic.cz>2024-07-23 19:39:45 +0200
commit931fa184846aa0634d9fbcc860be78ec31606612 (patch)
tree518240a35f1b6a7d263ed5df149e07f35a986468
parentMerge !1562: lib/rules: fix a bug in subnet computations (diff)
parentmanager/tests/packaging: better kdig check (diff)
downloadknot-resolver-931fa184846aa0634d9fbcc860be78ec31606612.tar.xz
knot-resolver-931fa184846aa0634d9fbcc860be78ec31606612.zip
Merge branch 'release-6.0.8' into 'master'v6.0.8
Release 6.0.8 See merge request knot/knot-resolver!1572
-rw-r--r--NEWS57
-rw-r--r--daemon/bindings/net_buffering.rst25
-rw-r--r--daemon/io.c38
-rw-r--r--daemon/lua/kres-gen-33.lua32
-rwxr-xr-xdaemon/lua/kres-gen.sh7
-rw-r--r--daemon/network.c5
-rw-r--r--daemon/network.h11
-rw-r--r--daemon/proxyv2.c4
-rw-r--r--daemon/session2.c55
-rw-r--r--daemon/session2.h42
-rw-r--r--daemon/tls.c19
-rw-r--r--daemon/worker.c16
-rw-r--r--daemon/worker.h6
-rw-r--r--distro/pkg/arch/PKGBUILD11
-rw-r--r--doc/dev/config-lua-network.rst9
l---------doc/dev/daemon-bindings-net_buffering.rst1
-rw-r--r--manager/pyproject.toml2
-rw-r--r--manager/setup.py2
-rwxr-xr-xmanager/tests/packaging/systemd_service.sh2
-rw-r--r--meson.build2
-rw-r--r--modules/workarounds/README.rst2
21 files changed, 271 insertions, 77 deletions
diff --git a/NEWS b/NEWS
index 28c6a1c9..1c115b1f 100644
--- a/NEWS
+++ b/NEWS
@@ -1,44 +1,70 @@
-Knot Resolver 6.0.8 (2024-0m-dd)
+Knot Resolver 6.0.8 (2024-07-23)
================================
+Security
+--------
+- reduce buffering of transmitted data, especially TCP-based in userspace
+ Also expose some of the new tweaks in lua:
+ (require 'ffi').C.the_worker.engine.net.tcp.user_timeout = 1000
+ (require 'ffi').C.the_worker.engine.net.listen_{tcp,udp}_buflens.{snd,rcv}
+
+Packaging
+---------
+
+- all packages:
+ - remove unused dependency on `libedit` (!1553)
+- deb packages:
+ - packages ``knot-resolver-core`` and ``knot-resolver-manager`` have
+ been merged into a single ``knot-resolver6`` package. Suffix packages
+ ``knot-resolver-*`` have been renamed to ``knot-resolver6-*``. This
+ change _should_ be transparent, but please do let us know if you
+ encounter any issues while updating. (!1549)
+ - package ``python3-prometheus-client`` is now only an optional dependency
+- rpm packages:
+ - packages ``knot-resolver-core`` and ``knot-resolver-manager`` have
+ been merged into a single ``knot-resolver`` package. This change
+ _should_ be transparent, but please do let us know if you encounter
+ any issues while updating. (!1549)
+ - bugfix: do not overwrite config.yaml (!1525)
+ - package ``python3-prometheus_client`` is now only an optional dependency
+- arch package:
+ - fix after they renamed a dependency (!1536)
+
Improvements
------------
- TLS (DoT, DoH): respect crypto policy overrides in OS (!1526)
-- arch package: fix after they renamed a dependency (!1536)
- manager: export metrics to JSON via management HTTP API (!1527)
-
* JSON is the new default metrics output format
* the ``prometheus-client`` Python package is now an optional dependency,
required only for Prometheus export to work
- cache: prefetching records
-
* predict module: prefetching expiring records moved to prefetch module
* prefetch module: new module to prefetch expiring records
- stats: add separate metrics for IPv6 and IPv4 (!1545)
-- remove unused dependency on `libedit` (!1553)
- add the fresh DNSSEC root key "KSK-2024" already, Key ID 38696 (!1556)
-
-- manager: policy-loader: new component for separate loading policy rules (!1540)
-
+- manager: policy-loader: new component for separate loading of policy rules (!1540)
The ``policy-loader`` ensures that configured policies are loaded into the rules database
where they are made available to all running kresd workers. This loading is no longer done
by all kresd workers as it was before, so this should significantly improve the resolver's
startup/reload time when loading large sets of policy rules, e.g. large RPZs.
-.. TODO: Change the link below to a versioned one when releasing.
-
Incompatible changes
--------------------
- cache: the ``cache.prediction`` configuration property has been reorganized
into ``cache.prefetch.expiring`` and ``cache.prefetch.prediction``, changing
the default behaviour as well. See the `relevant documentation section
- <https://www.knot-resolver.cz/documentation/latest/config-cache-predict.html>`_
+ <https://www.knot-resolver.cz/documentation/v6.0.8/config-cache-predict.html>`_
for more.
- libknot <=3.2.x support is dropped (!1565)
Bugfixes
--------
+- arch package: fix after they renamed a dependency (!1536)
- fix startup with `dnssec: false` (!1548)
+- rpm packages: do not overwrite config.yaml (!1525)
+- fix NSEC3 records missing in answer for positive wildcard expansion
+ with the NSEC3 having over-limit iteration count (#910, !1550)
+- views: fix a bug in subnet matching (!1562)
Knot Resolver 6.0.7 (2024-03-27)
@@ -115,9 +141,16 @@ https://www.knot-resolver.cz/documentation/latest/upgrading-to-6.html
5.x branch longterm support
~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Knot Resolver 5.7.4 (2024-0m-dd)
+Knot Resolver 5.7.4 (2024-07-23)
================================
+Security
+--------
+- reduce buffering of transmitted data, especially TCP-based in userspace
+ Also expose some of the new tweaks in lua:
+ (require 'ffi').C.the_worker.engine.net.tcp.user_timeout = 1000
+ (require 'ffi').C.the_worker.engine.net.listen_{tcp,udp}_buflens.{snd,rcv}
+
Improvements
------------
- add the fresh DNSSEC root key "KSK-2024" already, Key ID 38696 (!1556)
diff --git a/daemon/bindings/net_buffering.rst b/daemon/bindings/net_buffering.rst
new file mode 100644
index 00000000..946fc28e
--- /dev/null
+++ b/daemon/bindings/net_buffering.rst
@@ -0,0 +1,25 @@
+.. SPDX-License-Identifier: GPL-3.0-or-later
+
+Buffering tweaks
+----------------
+
+We (can) set various server-side socket options that affect buffering.
+The values are stored in C structures without real Lua bindings,
+so setting them is a bit long.
+
+.. py:data:: (require 'ffi').C.the_worker.engine.net.tcp.user_timeout
+
+ On TCP-based server-side sockets we set ``TCP_USER_TIMEOUT`` option if available (~Linux).
+ We use default 1000, i.e. one second. For details see the definition in ``man tcp.7``.
+
+.. py:data:: (require 'ffi').C.the_worker.engine.net.listen_tcp_buflens.snd
+.. py:data:: (require 'ffi').C.the_worker.engine.net.listen_tcp_buflens.rcv
+.. py:data:: (require 'ffi').C.the_worker.engine.net.listen_udp_buflens.snd
+.. py:data:: (require 'ffi').C.the_worker.engine.net.listen_udp_buflens.rcv
+
+ If overridden to nonzero, these variables instruct the OS to modify kernel-space buffers
+ for server-side sockets. We split the setting for UDP vs. TCP and sending vs. receiving.
+
+ For details see ``SO_SNDBUF`` and ``SO_RCVBUF`` in ``man socket.7``.
+ There is no user-space buffering beyond immediate manipulation, only the OS keeps some.
+
diff --git a/daemon/io.c b/daemon/io.c
index cf372787..86bd314e 100644
--- a/daemon/io.c
+++ b/daemon/io.c
@@ -165,15 +165,20 @@ static enum protolayer_event_cb_result pl_tcp_event_wrap(
enum protolayer_event_type event, void **baton,
struct session2 *session, void *sess_data)
{
- if (event == PROTOLAYER_EVENT_STATS_SEND_ERR) {
+ switch (event) {
+ case PROTOLAYER_EVENT_STATS_SEND_ERR:
the_worker->stats.err_tcp += 1;
return PROTOLAYER_EVENT_CONSUME;
- } else if (event == PROTOLAYER_EVENT_STATS_QRY_OUT) {
+ case PROTOLAYER_EVENT_STATS_QRY_OUT:
the_worker->stats.tcp += 1;
return PROTOLAYER_EVENT_CONSUME;
+ case PROTOLAYER_EVENT_OS_BUFFER_FULL:
+ session2_force_close(session);
+ return PROTOLAYER_EVENT_CONSUME;
+ default:
+ return PROTOLAYER_EVENT_PROPAGATE;
}
- return PROTOLAYER_EVENT_PROPAGATE;
}
__attribute__((constructor))
@@ -261,6 +266,17 @@ int io_bind(const struct sockaddr *addr, int type, const endpoint_flags_t *flags
return fd;
}
+/// Optionally set a socket option and log error on failure.
+static void set_so(int fd, int so_option, int value, const char *descr)
+{
+ if (!value) return;
+ if (setsockopt(fd, SOL_SOCKET, so_option, &value, sizeof(value))) {
+ kr_log_error(IO, "failed to set %s to %d: %s\n",
+ descr, value, strerror(errno));
+ // we treat this as non-critical failure
+ }
+}
+
int io_listen_udp(uv_loop_t *loop, uv_udp_t *handle, int fd)
{
if (!handle) {
@@ -272,6 +288,9 @@ int io_listen_udp(uv_loop_t *loop, uv_udp_t *handle, int fd)
ret = uv_udp_open(handle, fd);
if (ret) return ret;
+ set_so(fd, SO_SNDBUF, the_network->listen_udp_buflens.snd, "UDP send buffer size");
+ set_so(fd, SO_RCVBUF, the_network->listen_udp_buflens.rcv, "UDP receive buffer size");
+
uv_handle_t *h = (uv_handle_t *)handle;
check_bufsize(h);
/* Handle is already created, just create context. */
@@ -314,7 +333,7 @@ static void tcp_recv(uv_stream_t *handle, ssize_t nread, const uv_buf_t *buf)
uv_strerror(nread));
}
session2_penalize(s);
- worker_end_tcp(s);
+ session2_force_close(s);
return;
}
@@ -464,6 +483,17 @@ int io_listen_tcp(uv_loop_t *loop, uv_tcp_t *handle, int fd, int tcp_backlog, bo
}
#endif
+ /* These get inherited into the individual connections (on Linux at least). */
+ set_so(fd, SO_SNDBUF, the_network->listen_tcp_buflens.snd, "TCP send buffer size");
+ set_so(fd, SO_RCVBUF, the_network->listen_tcp_buflens.rcv, "TCP receive buffer size");
+#ifdef TCP_USER_TIMEOUT
+ val = the_network->tcp.user_timeout;
+ if (val && setsockopt(fd, IPPROTO_TCP, TCP_USER_TIMEOUT, &val, sizeof(val))) {
+ kr_log_error(IO, "listen TCP (user_timeout): %s\n", strerror(errno));
+ }
+ // TODO: also for upstream connections, at least this one option?
+#endif
+
handle->data = NULL;
return 0;
}
diff --git a/daemon/lua/kres-gen-33.lua b/daemon/lua/kres-gen-33.lua
index 77e69f2c..6be16bc4 100644
--- a/daemon/lua/kres-gen-33.lua
+++ b/daemon/lua/kres-gen-33.lua
@@ -509,6 +509,7 @@ int kr_rule_zonefile(const struct kr_rule_zonefile_config *);
int kr_rule_forward(const knot_dname_t *, kr_rule_fwd_flags_t, const struct sockaddr **);
int kr_rule_local_address(const char *, const char *, _Bool, uint32_t, kr_rule_tags_t);
int kr_rule_local_hosts(const char *, _Bool, uint32_t, kr_rule_tags_t);
+struct tls_credentials;
typedef struct {
int sock_type;
_Bool tls;
@@ -559,6 +560,36 @@ typedef struct {
zi_callback cb;
void *cb_param;
} zi_config_t;
+typedef struct uv_loop_s uv_loop_t;
+typedef struct trie tls_client_params_t;
+struct net_tcp_param {
+ uint64_t in_idle_timeout;
+ uint64_t tls_handshake_timeout;
+ unsigned int user_timeout;
+};
+struct network {
+ uv_loop_t *loop;
+ trie_t *endpoints;
+ trie_t *endpoint_kinds;
+ _Bool missing_kind_is_error : 1;
+ _Bool proxy_all4 : 1;
+ _Bool proxy_all6 : 1;
+ trie_t *proxy_addrs4;
+ trie_t *proxy_addrs6;
+ struct tls_credentials *tls_credentials;
+ tls_client_params_t *tls_client_params;
+ struct tls_session_ticket_ctx *tls_session_ticket_ctx;
+ struct net_tcp_param tcp;
+ int tcp_backlog;
+ struct {
+ int snd;
+ int rcv;
+ } listen_udp_buflens;
+ struct {
+ int snd;
+ int rcv;
+ } listen_tcp_buflens;
+};
struct args *the_args;
struct endpoint {
void *handle;
@@ -591,6 +622,7 @@ struct worker_ctx {
struct kr_context *the_resolver;
struct worker_ctx *the_worker;
struct engine *the_engine;
+struct network *the_network;
typedef struct {
uint8_t *params_position;
uint8_t *mandatory_position;
diff --git a/daemon/lua/kres-gen.sh b/daemon/lua/kres-gen.sh
index 8554a783..d335c0ec 100755
--- a/daemon/lua/kres-gen.sh
+++ b/daemon/lua/kres-gen.sh
@@ -312,6 +312,7 @@ EOF
## kresd itself: worker stuff
+echo "struct tls_credentials;"
${CDEFS} ${KRESD} types <<-EOF
endpoint_flags_t
@@ -322,6 +323,11 @@ ${CDEFS} ${KRESD} types <<-EOF
config_array_t
struct args
zi_config_t
+ # struct network - and all requirements that are missing so far
+ typedef uv_loop_t
+ typedef tls_client_params_t
+ struct net_tcp_param
+ struct network
EOF
echo "struct args *the_args;"
@@ -349,6 +355,7 @@ printf "\tchar _stub[];\n};\n"
echo "struct kr_context *the_resolver;"
echo "struct worker_ctx *the_worker;"
echo "struct engine *the_engine;"
+echo "struct network *the_network;"
## libzscanner API for ./zonefile.lua
diff --git a/daemon/network.c b/daemon/network.c
index 7d1d5155..59d47809 100644
--- a/daemon/network.c
+++ b/daemon/network.c
@@ -76,7 +76,12 @@ void network_init(uv_loop_t *loop, int tcp_backlog)
tls_session_ticket_ctx_create(loop, NULL, 0);
the_network->tcp.in_idle_timeout = 10000;
the_network->tcp.tls_handshake_timeout = TLS_MAX_HANDSHAKE_TIME;
+ the_network->tcp.user_timeout = 1000; // 1s should be more than enough
the_network->tcp_backlog = tcp_backlog;
+
+ // On Linux, unset means some auto-tuning mechanism also depending on RAM,
+ // which might be OK default (together with the user_timeout above)
+ //the_network->listen_{tcp,udp}_buflens.{snd,rcv}
}
/** Notify the registered function about endpoint getting open.
diff --git a/daemon/network.h b/daemon/network.h
index 9c667dbd..83d1b6f4 100644
--- a/daemon/network.h
+++ b/daemon/network.h
@@ -67,6 +67,10 @@ typedef array_t(struct endpoint) endpoint_array_t;
struct net_tcp_param {
uint64_t in_idle_timeout;
uint64_t tls_handshake_timeout;
+
+ /** Milliseconds of unacknowledged data; see TCP_USER_TIMEOUT in man tcp.7
+ * Linux only, probably. */
+ unsigned int user_timeout;
};
/** Information about an address that is allowed to use PROXYv2. */
@@ -104,6 +108,13 @@ struct network {
struct tls_session_ticket_ctx *tls_session_ticket_ctx;
struct net_tcp_param tcp;
int tcp_backlog;
+
+ /** Kernel-side buffer sizes for sending and receiving. (in bytes)
+ * They are per socket, so in the TCP case they are per connection.
+ * See SO_SNDBUF and SO_RCVBUF in man socket.7 These are in POSIX. */
+ struct {
+ int snd, rcv;
+ } listen_udp_buflens, listen_tcp_buflens;
};
/** Pointer to the singleton network state. NULL if not initialized. */
diff --git a/daemon/proxyv2.c b/daemon/proxyv2.c
index 110d3415..31eeb624 100644
--- a/daemon/proxyv2.c
+++ b/daemon/proxyv2.c
@@ -407,7 +407,7 @@ static enum protolayer_iter_cb_result pl_proxyv2_stream_unwrap(
"for this peer, close\n",
kr_straddr(peer));
}
- worker_end_tcp(s);
+ session2_force_close(s);
return protolayer_break(ctx, kr_error(ECONNRESET));
}
@@ -424,7 +424,7 @@ static enum protolayer_iter_cb_result pl_proxyv2_stream_unwrap(
kr_straddr(comm->src_addr));
}
}
- worker_end_tcp(s);
+ session2_force_close(s);
return protolayer_break(ctx, kr_error(ECONNRESET));
} else if (trimmed == 0) {
session2_close(s);
diff --git a/daemon/session2.c b/daemon/session2.c
index 09a4b362..0d1a69f5 100644
--- a/daemon/session2.c
+++ b/daemon/session2.c
@@ -395,19 +395,21 @@ static int protolayer_iter_ctx_finish(struct protolayer_iter_ctx *ctx, int ret)
globals->iter_deinit(ctx, d);
}
- if (ret)
+ if (ret) {
VERBOSE_LOG(s, "layer context of group '%s' (on %u: %s) ended with return code %d\n",
kr_proto_name(s->proto),
ctx->layer_ix, layer_name_ctx(ctx), ret);
+ }
- if (ctx->status)
- VERBOSE_LOG(s, "iteration of group '%s' (on %u: %s) ended with status %d\n",
+ if (ctx->status) {
+ VERBOSE_LOG(s, "iteration of group '%s' (on %u: %s) ended with status '%s (%d)'\n",
kr_proto_name(s->proto),
- ctx->layer_ix, layer_name_ctx(ctx), ctx->status);
+ ctx->layer_ix, layer_name_ctx(ctx),
+ kr_strerror(ctx->status), ctx->status);
+ }
if (ctx->finished_cb)
- ctx->finished_cb(ret, s, ctx->comm,
- ctx->finished_cb_baton);
+ ctx->finished_cb(ret, s, ctx->comm, ctx->finished_cb_baton);
mm_ctx_delete(&ctx->pool);
free(ctx);
@@ -1235,7 +1237,7 @@ static void session2_event_wrap(struct session2 *s, enum protolayer_event_type e
session2_transport_event(s, event, baton);
}
-void session2_event_unwrap(struct session2 *s, ssize_t start_ix, enum protolayer_event_type event, void *baton)
+static void session2_event_unwrap(struct session2 *s, ssize_t start_ix, enum protolayer_event_type event, void *baton)
{
bool cont;
const struct protolayer_grp *grp = &protolayer_grps[s->proto];
@@ -1256,8 +1258,9 @@ void session2_event_unwrap(struct session2 *s, ssize_t start_ix, enum protolayer
*
* TODO: This might be undesirable for cases with sub-sessions - the
* current idea is for the layers managing sub-sessions to just return
- * `false` on `event_unwrap`, but a more "automatic" mechanism may be
- * added when this is relevant, to make it less error-prone. */
+ * `PROTOLAYER_EVENT_CONSUME` on `event_unwrap`, but a more "automatic"
+ * mechanism may be added when this is relevant, to make it less
+ * error-prone. */
session2_event_wrap(s, event, baton);
}
@@ -1380,6 +1383,15 @@ static void session2_transport_pushv_ensure_long_lived(
*iovcnt = 1;
}
+/// Count the total size of an iovec[] in bytes.
+static inline size_t iovec_sum(const struct iovec iov[], const int iovcnt)
+{
+ size_t result = 0;
+ for (int i = 0; i < iovcnt; ++i)
+ result += iov[i].iov_len;
+ return result;
+}
+
static int session2_transport_pushv(struct session2 *s,
struct iovec *iov, int iovcnt,
bool iov_short_lived,
@@ -1434,6 +1446,11 @@ static int session2_transport_pushv(struct session2 *s,
int ret = uv_udp_try_send((uv_udp_t*)handle,
(uv_buf_t *)iov, iovcnt, comm->comm_addr);
if (ret == UV_EAGAIN) {
+ ret = kr_error(ENOBUFS);
+ session2_event(s, PROTOLAYER_EVENT_OS_BUFFER_FULL, NULL);
+ }
+
+ if (false && ret == UV_EAGAIN) { // XXX: see uv_try_write() below
uv_udp_send_t *req = malloc(sizeof(*req));
req->data = ctx;
session2_transport_pushv_ensure_long_lived(
@@ -1444,14 +1461,23 @@ static int session2_transport_pushv(struct session2 *s,
session2_transport_udp_pushv_finished);
if (ret)
session2_transport_udp_pushv_finished(req, ret);
- } else {
- session2_transport_pushv_finished(ret, ctx);
+ return ret;
}
+
+ session2_transport_pushv_finished(ret, ctx);
return ret;
}
} else if (handle->type == UV_TCP) {
int ret = uv_try_write((uv_stream_t *)handle, (uv_buf_t *)iov, iovcnt);
- if (ret == UV_EAGAIN) {
+ // XXX: queueing disabled for now if the OS can't accept the data.
+ // Typically that happens when OS buffers are full.
+ // We were missing any handling of partial write success, too.
+ if (ret == UV_EAGAIN || (ret >= 0 && ret != iovec_sum(iov, iovcnt))) {
+ ret = kr_error(ENOBUFS);
+ session2_event(s, PROTOLAYER_EVENT_OS_BUFFER_FULL, NULL);
+ }
+
+ if (false && ret == UV_EAGAIN) {
uv_write_t *req = malloc(sizeof(*req));
req->data = ctx;
session2_transport_pushv_ensure_long_lived(
@@ -1461,9 +1487,10 @@ static int session2_transport_pushv(struct session2 *s,
session2_transport_stream_pushv_finished);
if (ret)
session2_transport_stream_pushv_finished(req, ret);
- } else {
- session2_transport_pushv_finished(ret, ctx);
+ return ret;
}
+
+ session2_transport_pushv_finished(ret, ctx);
return ret;
#if ENABLE_XDP
} else if (handle->type == UV_POLL) {
diff --git a/daemon/session2.h b/daemon/session2.h
index dc602cca..604c43a1 100644
--- a/daemon/session2.h
+++ b/daemon/session2.h
@@ -312,23 +312,31 @@ typedef void (*protolayer_finished_cb)(int status, struct session2 *session,
* Event types are used to distinguish different events that can be passed to
* sessions using `session2_event()`. */
#define PROTOLAYER_EVENT_MAP(XX) \
- XX(CLOSE) /**< Sending this event closes the session gracefully -
- * i.e. layers add their standard disconnection
- * ceremony (e.g. `gnutls_bye()`). */\
- XX(FORCE_CLOSE) /**< Sending this event closes the session forcefully -
- * i.e. layers SHOULD NOT add any disconnection
- * ceremony, if avoidable. */\
- XX(CONNECT_TIMEOUT) /**< Signal that a connection could not be
- * established due to a timeout. */\
- XX(GENERAL_TIMEOUT) /**< Signal that a general application-defined
- * timeout has occurred. */\
- XX(CONNECT) /**< Signal that a connection has been established. */\
- XX(CONNECT_FAIL) /**< Signal that a connection could not have been
- * established. */\
- XX(MALFORMED) /**< Signal that a malformed request has been received. */\
- XX(DISCONNECT) /**< Signal that a connection has ended. */\
- XX(STATS_SEND_ERR) /**< Failed task send - update stats. */\
- XX(STATS_QRY_OUT) /**< Outgoing query submission - update stats. */
+ /** Closes the session gracefully - i.e. layers add their standard
+ * disconnection ceremony (e.g. `gnutls_bye()`). */\
+ XX(CLOSE) \
+ /** Closes the session forcefully - i.e. layers SHOULD NOT add any
+ * disconnection ceremony, if avoidable. */\
+ XX(FORCE_CLOSE) \
+ /** Signal that a connection could not be established due to a timeout. */\
+ XX(CONNECT_TIMEOUT) \
+ /** Signal that a general application-defined timeout has occurred. */\
+ XX(GENERAL_TIMEOUT) \
+ /** Signal that a connection has been established. */\
+ XX(CONNECT) \
+ /** Signal that a connection could not have been established. */\
+ XX(CONNECT_FAIL) \
+ /** Signal that a malformed request has been received. */\
+ XX(MALFORMED) \
+ /** Signal that a connection has ended. */\
+ XX(DISCONNECT) \
+ /** Failed task send - update stats. */\
+ XX(STATS_SEND_ERR) \
+ /** Outgoing query submission - update stats. */\
+ XX(STATS_QRY_OUT) \
+ /** OS buffers are full, so not sending any more data. */\
+ XX(OS_BUFFER_FULL) \
+ //
/** Event type, to be interpreted by a layer. */
enum protolayer_event_type {
diff --git a/daemon/tls.c b/daemon/tls.c
index c77c5c2b..173cf3c3 100644
--- a/daemon/tls.c
+++ b/daemon/tls.c
@@ -893,7 +893,21 @@ static int pl_tls_sess_data_deinit(struct pl_tls_sess_data *tls)
tls_credentials_release(tls->server_credentials);
}
wire_buf_deinit(&tls->unwrap_buf);
- queue_deinit(tls->unwrap_queue); /* TODO: break contexts? */
+
+ while (queue_len(tls->unwrap_queue) > 0) {
+ struct protolayer_iter_ctx *ctx = queue_head(tls->unwrap_queue);
+ protolayer_break(ctx, kr_error(EIO));
+ queue_pop(tls->unwrap_queue);
+ }
+ queue_deinit(tls->unwrap_queue);
+
+ while (queue_len(tls->wrap_queue)) {
+ struct protolayer_iter_ctx *ctx = queue_head(tls->wrap_queue);
+ protolayer_break(ctx, kr_error(EIO));
+ queue_pop(tls->wrap_queue);
+ }
+ queue_deinit(tls->wrap_queue);
+
return kr_ok();
}
@@ -1184,6 +1198,9 @@ static ssize_t pl_tls_submit(gnutls_session_t tls_session,
if (payload.type == PROTOLAYER_PAYLOAD_WIRE_BUF)
payload = protolayer_payload_as_buffer(&payload);
+ // TODO: the handling of positive gnutls_record_send() is weird/confusing,
+ // but it seems caught later when checking gnutls_record_uncork()
+
if (payload.type == PROTOLAYER_PAYLOAD_BUFFER) {
ssize_t count = gnutls_record_send(tls_session,
payload.buffer.buf, payload.buffer.len);
diff --git a/daemon/worker.c b/daemon/worker.c
index f620904c..caf11e55 100644
--- a/daemon/worker.c
+++ b/daemon/worker.c
@@ -585,7 +585,7 @@ int qr_task_on_send(struct qr_task *task, struct session2 *s, int status)
"=> disconnected from '%s': %s\n",
peer_str, uv_strerror(status));
}
- worker_end_tcp(s);
+ session2_force_close(s);
return status;
}
@@ -1287,7 +1287,7 @@ static int qr_task_step(struct qr_task *task,
static int worker_submit(struct session2 *session, struct comm_info *comm, knot_pkt_t *pkt)
{
- if (!session || !pkt)
+ if (!session || !pkt || session->closing)
return kr_error(EINVAL);
const bool is_query = pkt->size > KNOT_WIRE_OFFSET_FLAGS1
@@ -1469,16 +1469,6 @@ static struct session2* worker_find_tcp_waiting(const struct sockaddr* addr)
return trie_find_tcp_session(the_worker->tcp_waiting, addr);
}
-int worker_end_tcp(struct session2 *session)
-{
- if (!session)
- return kr_error(EINVAL);
-
- session2_timer_stop(session);
- session2_force_close(session);
- return kr_ok();
-}
-
knot_pkt_t *worker_resolve_mk_pkt_dname(knot_dname_t *qname, uint16_t qtype, uint16_t qclass,
const struct kr_qflags *options)
{
@@ -2188,7 +2178,7 @@ exit:
wire_buf_movestart(wb);
mp_flush(the_worker->pkt_pool.ctx);
if (status < 0)
- worker_end_tcp(session);
+ session2_force_close(session);
return protolayer_break(ctx, status);
}
diff --git a/daemon/worker.h b/daemon/worker.h
index 8f89e586..42614cc9 100644
--- a/daemon/worker.h
+++ b/daemon/worker.h
@@ -28,12 +28,6 @@ int worker_init(void);
/** Destroy the worker (free memory). */
void worker_deinit(void);
-/**
- * End current DNS/TCP session, this disassociates pending tasks from this session
- * which may be freely closed afterwards.
- */
-int worker_end_tcp(struct session2 *session);
-
KR_EXPORT knot_pkt_t *worker_resolve_mk_pkt_dname(knot_dname_t *qname, uint16_t qtype, uint16_t qclass,
const struct kr_qflags *options);
diff --git a/distro/pkg/arch/PKGBUILD b/distro/pkg/arch/PKGBUILD
index 619f562d..422da695 100644
--- a/distro/pkg/arch/PKGBUILD
+++ b/distro/pkg/arch/PKGBUILD
@@ -1,5 +1,8 @@
-# Maintainer: Tomas Krizek <tomas.krizek@nic.cz>
+# Maintainer: Knot Resolver team <knot-resolver@labs.nic.cz>
+# Maintainer: Vladimír Čunát <vladimir.cunat@nic.cz>
+# Contributor: Nicki Křížek <nicki@isc.org>
# Contributor: Ondřej Surý <ondrej@sury.org>
+# Contributor: Oto Šťáva <oto.stava@gmail.com>
# SPDX-License-Identifier: GPL-3.0-or-later
pkgname=knot-resolver
@@ -24,23 +27,25 @@ depends=(
'python-yaml'
'python-aiohttp'
'python-typing_extensions'
- 'python-prometheus_client'
'python-jinja'
'supervisor'
)
makedepends=(
'cmocka'
'meson'
- 'systemd-libs'
+ 'pkgconfig'
'python-build'
'python-installer'
'python-poetry'
+ 'python-wheel'
+ 'systemd-libs'
)
optdepends=(
'lua51-basexx: experimental_dot_auth module'
'lua51-cqueues: http and dns64 module, policy.rpz() function'
'lua51-http: http and prefill modules, trust_anchors bootstrap'
'lua51-psl: policy.slice_randomize_psl() function'
+ 'python-prometheus_client: stats and metrics in Prometheus format'
)
backup=('etc/knot-resolver/config.yaml')
options=(debug strip)
diff --git a/doc/dev/config-lua-network.rst b/doc/dev/config-lua-network.rst
index 241b67ff..d4f80646 100644
--- a/doc/dev/config-lua-network.rst
+++ b/doc/dev/config-lua-network.rst
@@ -61,3 +61,12 @@ DNS protocol tweaks
:maxdepth: 2
daemon-bindings-net_dns_tweaks
+
+Buffering tweaks
+================
+
+.. toctree::
+ :maxdepth: 2
+
+ daemon-bindings-net_buffering
+
diff --git a/doc/dev/daemon-bindings-net_buffering.rst b/doc/dev/daemon-bindings-net_buffering.rst
new file mode 120000
index 00000000..9386a5fa
--- /dev/null
+++ b/doc/dev/daemon-bindings-net_buffering.rst
@@ -0,0 +1 @@
+../../daemon/bindings/net_buffering.rst \ No newline at end of file
diff --git a/manager/pyproject.toml b/manager/pyproject.toml
index 256a3812..7f1bde1f 100644
--- a/manager/pyproject.toml
+++ b/manager/pyproject.toml
@@ -1,6 +1,6 @@
[tool.poetry]
name = "knot-resolver-manager"
-version = "6.0.7"
+version = "6.0.8"
description = "A central tool for managing individual parts of Knot Resolver"
authors = [
diff --git a/manager/setup.py b/manager/setup.py
index bbd244d7..e3abf0f1 100644
--- a/manager/setup.py
+++ b/manager/setup.py
@@ -30,7 +30,7 @@ entry_points = \
setup_kwargs = {
'name': 'knot-resolver-manager',
- 'version': '6.0.7',
+ 'version': '6.0.8',
'description': 'A central tool for managing individual parts of Knot Resolver',
'long_description': 'None',
'author': 'Aleš Mrázek',
diff --git a/manager/tests/packaging/systemd_service.sh b/manager/tests/packaging/systemd_service.sh
index 24f48071..c6ac826b 100755
--- a/manager/tests/packaging/systemd_service.sh
+++ b/manager/tests/packaging/systemd_service.sh
@@ -29,7 +29,7 @@ else
set +e
# check that the resolvers are actually running
- kdig @127.0.0.1 nic.cz
+ kdig @127.0.0.1 +edns nic.cz | tee /dev/stderr | grep -qi 'status: NOERROR'
if [ "$?" -ne "0" ]; then
echo "Could not 'kdig' the resolvers - are they running?"
exit 1
diff --git a/meson.build b/meson.build
index 4e2b6f7b..0e91427a 100644
--- a/meson.build
+++ b/meson.build
@@ -4,7 +4,7 @@ project(
'knot-resolver',
['c', 'cpp'],
license: 'GPLv3+',
- version: '6.0.7',
+ version: '6.0.8',
default_options: ['c_std=gnu11', 'b_ndebug=true'],
meson_version: '>=0.49',
)
diff --git a/modules/workarounds/README.rst b/modules/workarounds/README.rst
index fcb04aa3..f456c6c1 100644
--- a/modules/workarounds/README.rst
+++ b/modules/workarounds/README.rst
@@ -2,7 +2,7 @@
.. _mod-workarounds:
-Module `workarounds` resolver behavior on specific broken sub-domains.
+Module `workarounds` tweaks resolver behavior on specific broken sub-domains.
Currently it mainly disables case randomization.
.. code-block:: lua