summaryrefslogtreecommitdiffstats
path: root/modules/extended_error/extended_error.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/extended_error/extended_error.c')
-rw-r--r--modules/extended_error/extended_error.c47
1 files changed, 47 insertions, 0 deletions
diff --git a/modules/extended_error/extended_error.c b/modules/extended_error/extended_error.c
new file mode 100644
index 0000000..db0ed57
--- /dev/null
+++ b/modules/extended_error/extended_error.c
@@ -0,0 +1,47 @@
+#include <libknot/rrtype/opt.h>
+
+#include "lib/module.h"
+#include "daemon/engine.h"
+
+static int extended_error_finalize(kr_layer_t *ctx) {
+ struct kr_request *req = ctx->req;
+ const knot_rrset_t *src_opt = req->qsource.packet->opt_rr;
+ const struct kr_extended_error *ede = &req->extended_error;
+
+ if (ede->info_code == KNOT_EDNS_EDE_NONE /* no extended error */
+ || src_opt == NULL /* no EDNS in query */
+ || kr_fails_assert(ede->info_code >= 0 && ede->info_code < UINT16_MAX) /* info code out of range */
+ || kr_fails_assert(req->answer->opt_rr) /* sanity check - answer should have EDNS */
+ ) {
+ return ctx->state;
+ }
+
+ const uint16_t info_code = (uint16_t)ede->info_code;
+ const size_t extra_len = ede->extra_text ? strlen(ede->extra_text) : 0;
+ uint8_t buf[sizeof(info_code) + extra_len];
+ knot_wire_write_u16(buf, info_code);
+ if (extra_len)
+ memcpy(buf + sizeof(info_code), ede->extra_text, extra_len);
+
+ if (knot_edns_add_option(req->answer->opt_rr, KNOT_EDNS_OPTION_EDE,
+ sizeof(buf), buf, &req->pool) != KNOT_EOK) {
+ /* something went wrong and there is no way to salvage content of OPT RRset */
+ kr_log_req(req, 0, 0, EDE, "unable to add Extended Error option\n");
+ knot_rrset_clear(req->answer->opt_rr, &req->pool);
+ }
+
+ return ctx->state;
+}
+
+KR_EXPORT
+int extended_error_init(struct kr_module *module) {
+ static kr_layer_api_t layer = {
+ .answer_finalize = &extended_error_finalize,
+ };
+ layer.data = module;
+ module->layer = &layer;
+
+ return kr_ok();
+}
+
+KR_MODULE_EXPORT(extended_error)