summaryrefslogtreecommitdiffstats
path: root/modules/bogus_log/bogus_log.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/bogus_log/bogus_log.c')
-rw-r--r--modules/bogus_log/bogus_log.c135
1 files changed, 135 insertions, 0 deletions
diff --git a/modules/bogus_log/bogus_log.c b/modules/bogus_log/bogus_log.c
new file mode 100644
index 0000000..7b36187
--- /dev/null
+++ b/modules/bogus_log/bogus_log.c
@@ -0,0 +1,135 @@
+/* Copyright (C) Knot Resolver contributors
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ *
+ * This module logs (query name, type) pairs which failed DNSSEC validation. */
+
+#include <libknot/packet/pkt.h>
+#include <libknot/dname.h>
+#include <ccan/json/json.h>
+#include <contrib/cleanup.h>
+
+#include "daemon/engine.h"
+#include "lib/layer.h"
+#include "lib/generic/lru.h"
+
+#ifdef LRU_REP_SIZE
+ #define FREQUENT_COUNT LRU_REP_SIZE /* Size of frequent tables */
+#else
+ #define FREQUENT_COUNT 5000 /* Size of frequent tables */
+#endif
+
+/** @internal LRU hash of most frequent names. */
+typedef lru_t(unsigned) namehash_t;
+
+/** @internal Stats data structure. */
+struct stat_data {
+ namehash_t *frequent;
+};
+
+static int consume(kr_layer_t *ctx, knot_pkt_t *pkt)
+{
+ if (!(ctx->state & KR_STATE_FAIL)
+ || !ctx->req
+ || !ctx->req->current_query
+ || !ctx->req->current_query->flags.DNSSEC_BOGUS
+ || knot_wire_get_qdcount(pkt->wire) != 1)
+ return ctx->state;
+
+ auto_free char *qname_text = kr_dname_text(knot_pkt_qname(pkt));
+ auto_free char *qtype_text = kr_rrtype_text(knot_pkt_qtype(pkt));
+
+ kr_log_notice(DNSSEC, "validation failure: %s %s\n", qname_text, qtype_text);
+
+ /* log of most frequent bogus queries */
+ uint16_t type = knot_pkt_qtype(pkt);
+ char key[sizeof(type) + KNOT_DNAME_MAXLEN];
+ memcpy(key, &type, sizeof(type));
+ int key_len = knot_dname_to_wire((uint8_t *)key + sizeof(type), knot_pkt_qname(pkt), KNOT_DNAME_MAXLEN);
+ if (key_len >= 0) {
+ struct kr_module *module = ctx->api->data;
+ struct stat_data *data = module->data;
+ unsigned *count = lru_get_new(data->frequent, key, key_len+sizeof(type), NULL);
+ if (count)
+ *count += 1;
+ }
+
+ return ctx->state;
+}
+
+/** @internal Helper for dump_list: add a single namehash_t item to JSON. */
+static enum lru_apply_do dump_value(const char *key, uint len, unsigned *val, void *baton)
+{
+ uint16_t key_type = 0;
+ /* Extract query name, type and counter */
+ memcpy(&key_type, key, sizeof(key_type));
+ KR_DNAME_GET_STR(key_name, (uint8_t *)key + sizeof(key_type));
+ KR_RRTYPE_GET_STR(type_str, key_type);
+
+ /* Convert to JSON object */
+ JsonNode *json_val = json_mkobject();
+ json_append_member(json_val, "count", json_mknumber(*val));
+ json_append_member(json_val, "name", json_mkstring(key_name));
+ json_append_member(json_val, "type", json_mkstring(type_str));
+ json_append_element((JsonNode *)baton, json_val);
+ return LRU_APPLY_DO_NOTHING; // keep the item
+}
+
+/**
+ * List frequent names.
+ *
+ * Output: [{ count: <counter>, name: <qname>, type: <qtype>}, ... ]
+ */
+static char* dump_list(void *env, struct kr_module *module, const char *args, namehash_t *table)
+{
+ if (!table) {
+ return NULL;
+ }
+ JsonNode *root = json_mkarray();
+ lru_apply(table, dump_value, root);
+ char *ret = json_encode(root);
+ json_delete(root);
+ return ret;
+}
+
+static char* dump_frequent(void *env, struct kr_module *module, const char *args)
+{
+ struct stat_data *data = module->data;
+ return dump_list(env, module, args, data->frequent);
+}
+
+KR_EXPORT
+int bogus_log_init(struct kr_module *module)
+{
+ static kr_layer_api_t layer = {
+ .consume = &consume,
+ };
+ layer.data = module;
+ module->layer = &layer;
+
+ static const struct kr_prop props[] = {
+ { &dump_frequent, "frequent", "List most frequent queries.", },
+ { NULL, NULL, NULL }
+ };
+ module->props = props;
+
+ struct stat_data *data = calloc(1, sizeof(*data));
+ if (!data) {
+ return kr_error(ENOMEM);
+ }
+ module->data = data;
+ lru_create(&data->frequent, FREQUENT_COUNT, NULL, NULL);
+ return kr_ok();
+}
+
+KR_EXPORT
+int bogus_log_deinit(struct kr_module *module)
+{
+ struct stat_data *data = module->data;
+ if (data) {
+ lru_free(data->frequent);
+ free(data);
+ }
+ return kr_ok();
+}
+
+KR_MODULE_EXPORT(bogus_log)