1
0
Fork 0
knot-resolver/modules/bogus_log/bogus_log.c
Daniel Baumann fbc604e215
Adding upstream version 5.7.5.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-21 13:56:17 +02:00

135 lines
3.6 KiB
C

/* 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)