From: Oto Šťáva Date: Mon, 27 May 2024 10:59:51 +0000 (+0200) Subject: Non-trivial merge 'master-5' (see 'modules/stats') X-Git-Tag: v6.0.8~18^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fenvironments%2Fdocs-develop-stat-s8hiue%2Fdeployments%2F4185;p=thirdparty%2Fknot-resolver.git Non-trivial merge 'master-5' (see 'modules/stats') modules/stats: adapt aggregate stats to the new hierarchical format Knot Resolver 6 changed the structure of the stats return value, making it more hierarchical, i.e. the returned object contains nested "sub-objects", rather than being flat. This commit adapts the new aggregate stats to this new structure, for consistency. --- 2babf205f404701c03af3b90502ee9e2063d6bdc diff --cc NEWS index 9b3ed72ad,dca743864..6ed72b263 --- a/NEWS +++ b/NEWS @@@ -1,105 -1,10 +1,113 @@@ +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) + +.. 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 + `_ + for more. + + +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.3 (2024-0m-dd) + ================================ + + Improvements + ------------ + - stats: add separate metrics for IPv6 and IPv4 (!1544) + Knot Resolver 5.7.2 (2024-03-27) ================================ diff --cc modules/stats/stats.c index 4f2fb4051,367961521..deed9c949 --- a/modules/stats/stats.c +++ b/modules/stats/stats.c @@@ -72,6 -65,28 +73,29 @@@ static struct const_metric_elm const_me CONST_METRICS(X) #undef X }; + + /// These metrics are read-only views, each simply summing a pair of const_metrics items. + struct sum_metric { - const char *key; ++ const char *sub_key; + const size_t *val1, *val2; + }; + static const struct sum_metric sum_metrics[] = { + // We're using this to aggregate v4 + v6 pairs. + #define DEF(proto) { \ - .key = "request." #proto, \ ++ .sub_key = #proto, \ + .val1 = &const_metrics[metric_request_ ## proto ## 4].val, \ + .val2 = &const_metrics[metric_request_ ## proto ## 6].val, \ + } + DEF(udp), + DEF(tcp), + DEF(xdp), + DEF(dot), + DEF(doh), + #undef DEF + }; + static const size_t sum_metrics_len = sizeof(sum_metrics) / sizeof(sum_metrics[0]); ++#define SUM_METRICS_SUP_KEY "request" + /** @endcond */ /** @internal LRU hash of most frequent names. */ @@@ -335,6 -358,16 +367,16 @@@ static char* stats_get(void *env, struc return str_value; } } + /* Check if it exists in aggregate metrics. */ + for (int i = 0; i < sum_metrics_len; ++i) { + const struct sum_metric *smi = &sum_metrics[i]; - if (strcmp(smi->key, args) == 0) { ++ if (strcmp(smi->sub_key, args) == 0) { + ret = asprintf(&str_value, "%zu", *smi->val1 + *smi->val2); + if (ret < 0) + return NULL; + return str_value; + } + } /* Check in variable map */ trie_val_t *val = trie_get_try(data->trie, args, strlen(args)); if (!val) @@@ -360,6 -393,6 +402,24 @@@ struct list_entry_context size_t key_prefix_len; /**< Prefix length. Prefix is a wildcard if zero. */ }; ++/** Ensures that the `root` node contains an object (and only an object - not a ++ * number, array, or anything else) with the specified `key`. If this cannot be ++ * ensured, fails on an assertion, or returns `NULL` if asserts are disabled. */ ++static JsonNode *ensure_object(JsonNode *root, const char *key) ++{ ++ JsonNode *node = json_find_member(root, key); ++ if (node) { ++ if (kr_fails_assert(node->tag == JSON_OBJECT)) ++ return NULL; ++ } else { ++ node = json_mkobject(); ++ if (kr_fails_assert(node)) ++ return NULL; ++ json_append_member(root, key, node); ++ } ++ return node; ++} ++ /** Inserts the entry with a matching key into the JSON object. */ static int list_entry(const char *key, uint32_t key_len, trie_val_t *val, void *baton) { @@@ -367,33 -400,8 +427,27 @@@ if (!key_matches_prefix(key, key_len, ctx->key_prefix, ctx->key_prefix_len)) return 0; size_t number = (size_t)*val; - auto_free char *key_nt = strndup(key, key_len); - json_append_member(ctx->root, key_nt, json_mknumber((double)number)); + + uint32_t dot_index = 0; + for (uint32_t i = 0; i < key_len; i++) { + if (!key[i]) + break; + if (key[i] == '.') { + dot_index = i; + } + } + + if (dot_index) { + auto_free char *sup_key_nt = strndup(key, dot_index); + auto_free char *sub_key_nt = strndup(key + dot_index + 1, key_len - dot_index - 1); - JsonNode *sup = json_find_member(ctx->root, sup_key_nt); - if (!sup) { - sup = json_mkobject(); - if (kr_fails_assert(sup)) - return 0; - json_append_member(ctx->root, sup_key_nt, sup); - } - if (kr_fails_assert(sup)) ++ JsonNode *sup = ensure_object(ctx->root, sup_key_nt); ++ if (!sup) + return 0; + json_append_member(sup, sub_key_nt, json_mknumber((double)number)); + } else { + auto_free char *key_nt = strndup(key, key_len); + json_append_member(ctx->root, key_nt, json_mknumber((double)number)); + } return 0; } @@@ -404,24 -412,22 +458,36 @@@ */ static char* stats_list(void *env, struct kr_module *module, const char *args) { ++ char *ret; JsonNode *root = json_mkobject(); /* Walk const metrics map */ size_t args_len = args ? strlen(args) : 0; for (unsigned i = 0; i < metric_const_end; ++i) { struct const_metric_elm *elm = &const_metrics[i]; - if (!args || strncmp(elm->key, args, args_len) == 0) { - json_append_member(root, elm->key, json_mknumber((double)elm->val)); + if (!args || strcmp(elm->sup_key, args) == 0) { - JsonNode *sup = json_find_member(root, elm->sup_key); ++ JsonNode *sup = ensure_object(root, elm->sup_key); + if (!sup) { - sup = json_mkobject(); - if (kr_fails_assert(sup)) - break; - json_append_member(root, elm->sup_key, sup); ++ ret = strdup("\"ERROR\""); ++ goto exit; + } - if (kr_fails_assert(sup)) - break; + json_append_member(sup, elm->sub_key, json_mknumber((double)elm->val)); } } ++ ++ /* Walk sum metrics map */ ++ JsonNode *sum_sup = ensure_object(root, SUM_METRICS_SUP_KEY); ++ if (!sum_sup) { ++ ret = strdup("\"ERROR\""); ++ goto exit; ++ } + for (int i = 0; i < sum_metrics_len; ++i) { + const struct sum_metric *elm = &sum_metrics[i]; - if (!args || strncmp(elm->key, args, args_len) == 0) { ++ if (!args || strncmp(elm->sub_key, args, args_len) == 0) { + size_t val = *elm->val1 + *elm->val2; - json_append_member(root, elm->key, json_mknumber(val)); ++ json_append_member(sum_sup, elm->sub_key, json_mknumber(val)); + } + } ++ struct list_entry_context ctx = { .root = root, .key_prefix = args, @@@ -429,7 -435,7 +495,8 @@@ }; struct stat_data *data = module->data; trie_apply_with_key(data->trie, list_entry, &ctx); -- char *ret = json_encode(root); ++ ret = json_encode(root); ++exit: json_delete(root); return ret; }