- Knot Resolver 5.7.3 (2024-0m-dd)
+Knot Resolver 6.0.8 (2024-0m-dd)
+================================
+
+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)
+
+ 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>`_
+ for more.
+
+Bugfixes
+--------
+- fix startup with `dnssec: false` (!1548)
+
+
+Knot Resolver 6.0.7 (2024-03-27)
+================================
+
+Improvements
+------------
+- manager: clear the cache via management HTTP API (#876, !1491)
+- manager: added support for Python 3.12 and removed for 3.7 (!1502)
+- manager: use build-time install prefix to execute `kresd` instead of PATH (!1511)
+- docs: documentation is now separated into user and developer parts (!1514)
+- daemon: ignore UDP requests from ports < 1024 (!1507)
+- manager: increase startup timeout for processes (!1518, !1520)
+- local-data: increase default DB size to 2G on 64-bit platforms (!1518)
+
+Bugfixes
+--------
+- fix listening by interface name containing dashes (#900, !1500)
+- fix kresctl http request timeout (!1505)
+- fix RPZ if it contains apex NS record (!1516)
+- fix RPZ if SOA is repated, as usual in AXFR output (!1521)
+- avoid RPZ overriding the root SOA (!1521)
+- fix on 32-bit systems with 64-bit time_t (!1510)
+- fix paths to knot-dns libs if exec_prefix != prefix (!1503)
+- manager: add missing early check that neither a custom port nor TLS is set for
+ authoritative server forwarding (#902, !1505)
+
+
+Knot Resolver 6.0.6 (2024-02-13)
+================================
+
+Security
+--------
+- CVE-2023-50868: NSEC3 closest encloser proof can exhaust CPU
+
+ * validator: lower the NSEC3 iteration limit (150 -> 50)
+ * validator: similarly also limit excessive NSEC3 salt length
+ * cache: limit the amount of work on SHA1 in NSEC3 aggressive cache
+ * validator: limit the amount of work on SHA1 in NSEC3 proofs
+ * validator: refuse to validate answers with more than 8 NSEC3 records
+
+- CVE-2023-50387 "KeyTrap": DNSSEC verification complexity
+ could be exploited to exhaust CPU resources and stall DNS resolvers.
+ Solution boils down mainly to limiting crypto-validations per packet.
+
+ We would like to thank Elias Heftrig, Haya Schulmann, Niklas Vogel and Michael Waidner
+ from the German National Research Center for Applied Cybersecurity ATHENE
+ for bringing this vulnerability to our attention.
+
+Improvements
+------------
+- update addresses of B.root-servers.net (!1478)
+- tweak the default run_dir on non-Linux (!1481)
+
+Bugfixes
+--------
+- fix potential SERVFAIL deadlocks if net.ipv6 = false (#880)
+- fix validation of RRsets around 64 KiB size; needs libknot >= 3.4 (!1497)
+
+
+Knot Resolver 6.0.5 (2024-01-09)
+================================
+
+6.0.x are "early access" versions,
+not generally recommended for production use.
+
+6.0 contains biggest changes in the history of Knot Resolver releases.
+You will have to rewrite your configuration. See documentation, in particular:
+https://www.knot-resolver.cz/documentation/latest/upgrading-to-6.html
+
+
+
+
+5.x branch longterm support
+~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ Knot Resolver 5.7.4 (2024-06-dd)
+ ================================
+
+ Improvements
+ ------------
+ - add the fresh DNSSEC root key "KSK-2024" already, Key ID 38696 (!1556)
+
+
+ Knot Resolver 5.7.3 (2024-05-30)
================================
Improvements
*
* \returns GNUTLS_E_SUCCESS if certificate chain is valid, any other value is an error
*/
- static int client_verify_certchain(gnutls_session_t tls_session, const char *hostname)
-static int client_verify_certchain(struct tls_common_ctx *ctx, const char *hostname)
++static int client_verify_certchain(struct pl_tls_sess_data *tls, const char *hostname)
{
if (kr_fails_assert(hostname)) {
kr_log_error(TLSCLIENT, "internal config inconsistency: no hostname set\n");
}
unsigned int status;
- int ret = gnutls_certificate_verify_peers3(tls_session, hostname, &status);
- int ret = gnutls_certificate_verify_peers3(ctx->tls_session, hostname, &status);
++ int ret = gnutls_certificate_verify_peers3(tls->tls_session, hostname, &status);
if ((ret == GNUTLS_E_SUCCESS) && (status == 0)) {
return GNUTLS_E_SUCCESS;
}
- const char *addr_str = kr_straddr(session_get_peer(ctx->session));
++ const char *addr_str = kr_straddr(session2_get_peer(tls->h.session));
if (ret == GNUTLS_E_SUCCESS) {
gnutls_datum_t msg;
ret = gnutls_certificate_verification_status_print(
- status, gnutls_certificate_type_get(tls_session), &msg, 0);
- status, gnutls_certificate_type_get(ctx->tls_session), &msg, 0);
++ status, gnutls_certificate_type_get(tls->tls_session), &msg, 0);
if (ret == GNUTLS_E_SUCCESS) {
- kr_log_error(TLSCLIENT, "failed to verify peer certificate: "
- "%s\n", msg.data);
+ kr_log_error(TLSCLIENT, "failed to verify peer certificate of %s: "
+ "%s\n", addr_str, msg.data);
gnutls_free(msg.data);
} else {
- kr_log_error(TLSCLIENT, "failed to verify peer certificate: "
+ kr_log_error(TLSCLIENT, "failed to verify peer certificate of %s: "
"unable to print reason: %s (%s)\n",
+ addr_str,
gnutls_strerror(ret), gnutls_strerror_name(ret));
} /* gnutls_certificate_verification_status_print end */
} else {
return GNUTLS_E_CERTIFICATE_ERROR;
}
- if (ctx->params->pins.len > 0)
+ if (tls->client_params->pins.len > 0)
/* check hash of the certificate but ignore everything else */
- return client_verify_pin(cert_list_size, cert_list, ctx->params);
+ return client_verify_pin(cert_list_size, cert_list, tls->client_params);
else
- return client_verify_certchain(tls->tls_session, tls->client_params->hostname);
- return client_verify_certchain(&ctx->c, ctx->params->hostname);
++ return client_verify_certchain(tls, tls->client_params->hostname);
}
-struct tls_client_ctx *tls_client_ctx_new(tls_client_param_t *entry,
- struct worker_ctx *worker)
+static int tls_pull_timeout_func(gnutls_transport_ptr_t h, unsigned int ms)
{
- struct tls_client_ctx *ctx = calloc(1, sizeof (struct tls_client_ctx));
- if (!ctx) {
- return NULL;
+ struct pl_tls_sess_data *tls = h;
+ if (kr_fails_assert(tls)) {
+ errno = EFAULT;
+ return -1;
+ }
+
+ size_t avail = protolayer_queue_count_payload(&tls->unwrap_queue);
+ VERBOSE_MSG(tls->client_side, "timeout check: available: %zu\n", avail);
+ if (!avail) {
+ errno = EAGAIN;
+ return -1;
+ }
+ return avail;
+}
+
+static int pl_tls_sess_data_deinit(struct pl_tls_sess_data *tls)
+{
+ if (tls->tls_session) {
+ /* Don't terminate TLS connection, just tear it down */
+ gnutls_deinit(tls->tls_session);
+ tls->tls_session = NULL;
}
+
+ if (tls->client_side) {
+ tls_client_param_unref(tls->client_params);
+ } else {
+ tls_credentials_release(tls->server_credentials);
+ }
+ wire_buf_deinit(&tls->unwrap_buf);
+ queue_deinit(tls->unwrap_queue); /* TODO: break contexts? */
+ return kr_ok();
+}
+
+static int pl_tls_sess_server_init(struct session2 *session,
+ struct pl_tls_sess_data *tls)
+{
+ if (kr_fails_assert(the_worker && the_engine))
+ return kr_error(EINVAL);
+
+ if (!the_network->tls_credentials) {
+ the_network->tls_credentials = tls_get_ephemeral_credentials();
+ if (!the_network->tls_credentials) {
+ kr_log_error(TLS, "X.509 credentials are missing, and ephemeral credentials failed; no TLS\n");
+ return kr_error(EINVAL);
+ }
+ kr_log_info(TLS, "Using ephemeral TLS credentials\n");
+ tls_credentials_log_pins(the_network->tls_credentials);
+ }
+
+ time_t now = time(NULL);
+ if (the_network->tls_credentials->valid_until != GNUTLS_X509_NO_WELL_DEFINED_EXPIRATION) {
+ if (the_network->tls_credentials->ephemeral_servicename) {
+ /* ephemeral cert: refresh if due to expire within a week */
+ if (now >= the_network->tls_credentials->valid_until - EPHEMERAL_CERT_EXPIRATION_SECONDS_RENEW_BEFORE) {
+ struct tls_credentials *newcreds = tls_get_ephemeral_credentials();
+ if (newcreds) {
+ tls_credentials_release(the_network->tls_credentials);
+ the_network->tls_credentials = newcreds;
+ kr_log_info(TLS, "Renewed expiring ephemeral X.509 cert\n");
+ } else {
+ kr_log_error(TLS, "Failed to renew expiring ephemeral X.509 cert, using existing one\n");
+ }
+ }
+ } else {
+ /* non-ephemeral cert: warn once when certificate expires */
+ if (now >= the_network->tls_credentials->valid_until) {
+ kr_log_error(TLS, "X.509 certificate has expired!\n");
+ the_network->tls_credentials->valid_until = GNUTLS_X509_NO_WELL_DEFINED_EXPIRATION;
+ }
+ }
+ }
+
+ int flags = GNUTLS_SERVER | GNUTLS_NONBLOCK;
+#if GNUTLS_VERSION_NUMBER >= 0x030705
+ if (gnutls_check_version("3.7.5"))
+ flags |= GNUTLS_NO_TICKETS_TLS12;
+#endif
+ int ret = gnutls_init(&tls->tls_session, flags);
+ if (ret != GNUTLS_E_SUCCESS) {
+ kr_log_error(TLS, "gnutls_init(): %s (%d)\n", gnutls_strerror_name(ret), ret);
+ pl_tls_sess_data_deinit(tls);
+ return ret;
+ }
+
+ tls->server_credentials = tls_credentials_reserve(the_network->tls_credentials);
+ ret = gnutls_credentials_set(tls->tls_session, GNUTLS_CRD_CERTIFICATE,
+ tls->server_credentials->credentials);
+ if (ret != GNUTLS_E_SUCCESS) {
+ kr_log_error(TLS, "gnutls_credentials_set(): %s (%d)\n", gnutls_strerror_name(ret), ret);
+ pl_tls_sess_data_deinit(tls);
+ return ret;
+ }
+
+ ret = kres_gnutls_set_priority(tls->tls_session);
+ if (ret != GNUTLS_E_SUCCESS) {
+ pl_tls_sess_data_deinit(tls);
+ return ret;
+ }
+
+ tls->client_side = false;
+ wire_buf_init(&tls->unwrap_buf, UNWRAP_BUF_SIZE);
+
+ gnutls_transport_set_pull_function(tls->tls_session, kres_gnutls_pull);
+ gnutls_transport_set_vec_push_function(tls->tls_session, kres_gnutls_vec_push);
+ gnutls_transport_set_ptr(tls->tls_session, tls);
+
+ if (the_network->tls_session_ticket_ctx) {
+ tls_session_ticket_enable(the_network->tls_session_ticket_ctx,
+ tls->tls_session);
+ }
+
+ const gnutls_datum_t *alpn = &tls_grp_alpn[session->proto];
+ if (alpn->size) { /* ALPN is a non-empty string */
+ flags = 0;
+#if GNUTLS_VERSION_NUMBER >= 0x030500
+ /* Mandatory ALPN means the protocol must match if and
+ * only if ALPN extension is used by the client. */
+ flags |= GNUTLS_ALPN_MANDATORY;
+#endif
+
+ ret = gnutls_alpn_set_protocols(tls->tls_session, alpn, 1, flags);
+ if (ret != GNUTLS_E_SUCCESS) {
+ kr_log_error(TLS, "gnutls_alpn_set_protocols(): %s (%d)\n", gnutls_strerror_name(ret), ret);
+ pl_tls_sess_data_deinit(tls);
+ return ret;
+ }
+ }
+
+ return kr_ok();
+}
+
+static int pl_tls_sess_client_init(struct session2 *session,
+ struct pl_tls_sess_data *tls,
+ tls_client_param_t *param)
+{
unsigned int flags = GNUTLS_CLIENT | GNUTLS_NONBLOCK
#ifdef GNUTLS_ENABLE_FALSE_START
| GNUTLS_ENABLE_FALSE_START