1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
/* Copyright (C) Knot Resolver contributors. Licensed under GNU GPLv3 or
* (at your option) any later version. See COPYING for text of the license.
*
* This module provides NSID support according to RFC 5001. */
#include <libknot/packet/pkt.h>
#include <contrib/cleanup.h>
#include <ccan/json/json.h>
#include <lauxlib.h>
#include "daemon/engine.h"
#include "lib/layer.h"
struct nsid_config {
uint8_t *local_nsid;
size_t local_nsid_len;
};
static int nsid_finalize(kr_layer_t *ctx) {
const struct kr_module *module = ctx->api->data;
const struct nsid_config *config = module->data;
struct kr_request *req = ctx->req;
/* no local NSID configured, do nothing */
if (config->local_nsid == NULL)
return ctx->state;
const knot_rrset_t *src_opt = req->qsource.packet->opt_rr;
/* no EDNS in request, do nothing */
if (src_opt == NULL)
return ctx->state;
const uint8_t *req_nsid = knot_edns_get_option(src_opt, KNOT_EDNS_OPTION_NSID);
/* NSID option must be explicitly requested */
if (req_nsid == NULL)
return ctx->state;
/* Check violation of https://tools.ietf.org/html/rfc5001#section-2.1:
* The resolver MUST NOT include any NSID payload data in the query */
if (knot_edns_opt_get_length(req_nsid) != 0)
kr_log_verbose("[%05u. ][nsid] FORMERR: NSID option in query "
"must not contain payload, continuing\n", req->uid);
/* FIXME: actually change RCODE in answer to FORMERR? */
/* Sanity check, answer should have EDNS as well but who knows ... */
if (req->answer->opt_rr == NULL)
return ctx->state;
if (knot_edns_add_option(req->answer->opt_rr, KNOT_EDNS_OPTION_NSID,
config->local_nsid_len, config->local_nsid,
&req->pool) != KNOT_EOK) {
/* something went wrong and there is no way to salvage content of OPT RRset */
kr_log_verbose("[%05u. ][nsid] unable to add NSID option\n", req->uid);
knot_rrset_clear(req->answer->opt_rr, &req->pool);
}
return ctx->state;
}
KR_EXPORT
const kr_layer_api_t *nsid_layer(struct kr_module *module)
{
static kr_layer_api_t _layer = {
.answer_finalize = &nsid_finalize,
};
_layer.data = module;
return &_layer;
}
KR_EXPORT
int nsid_init(struct kr_module *module) {
struct nsid_config *config = calloc(1, sizeof(struct nsid_config));
if (config == NULL)
return kr_error(ENOMEM);
module->data = config;
return kr_ok();
}
static char* nsid_name(void *env, struct kr_module *module, const char *args)
{
struct engine *engine = env;
struct nsid_config *config = module->data;
if (args) { /* set */
/* API is not binary safe, we need to fix this one day */
uint8_t *arg_copy = (uint8_t *)strdup(args);
if (arg_copy == NULL)
luaL_error(engine->L, "[nsid] error while allocating new NSID value\n");
free(config->local_nsid);
config->local_nsid = arg_copy;
config->local_nsid_len = strlen(args);
}
/* get */
if (config->local_nsid != NULL)
return json_encode_string((char *)config->local_nsid);
else
return NULL;
}
KR_EXPORT
struct kr_prop *nsid_props(void)
{
static struct kr_prop prop_list[] = {
{ &nsid_name, "name", "Get or set local NSID value" },
{ NULL, NULL, NULL }
};
return prop_list;
}
KR_EXPORT
int nsid_deinit(struct kr_module *module) {
struct nsid_config *config = module->data;
if (config != NULL) {
free(config->local_nsid);
free(config);
module->data = NULL;
}
return kr_ok();
}
KR_MODULE_EXPORT(nsid)
|