summaryrefslogtreecommitdiffstats
path: root/modules/hints/hints.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/hints/hints.c')
-rw-r--r--modules/hints/hints.c361
1 files changed, 117 insertions, 244 deletions
diff --git a/modules/hints/hints.c b/modules/hints/hints.c
index 25d41c90..ccbc9880 100644
--- a/modules/hints/hints.c
+++ b/modules/hints/hints.c
@@ -20,6 +20,7 @@
#include "lib/zonecut.h"
#include "lib/module.h"
#include "lib/layer.h"
+#include "lib/rules/api.h"
#include <inttypes.h>
#include <math.h>
@@ -29,8 +30,6 @@
#define ERR_MSG(...) kr_log_error(HINT, "[ ]" __VA_ARGS__)
struct hints_data {
- struct kr_zonecut hints;
- struct kr_zonecut reverse_hints;
bool use_nodata; /**< See hint_use_nodata() description, exposed via lua. */
uint32_t ttl; /**< TTL used for the hints, exposed via lua. */
};
@@ -45,130 +44,6 @@ static char * bool2jsonstr(bool val)
return result;
}
-static int put_answer(knot_pkt_t *pkt, struct kr_query *qry, knot_rrset_t *rr, bool use_nodata)
-{
- int ret = 0;
- if (!knot_rrset_empty(rr) || use_nodata) {
- /* Update packet question */
- if (!knot_dname_is_equal(knot_pkt_qname(pkt), rr->owner)) {
- kr_pkt_recycle(pkt);
- knot_pkt_put_question(pkt, qry->sname, qry->sclass, qry->stype);
- }
- if (!knot_rrset_empty(rr)) {
- /* Append to packet */
- ret = knot_pkt_put_rotate(pkt, KNOT_COMPR_HINT_QNAME, rr,
- qry->reorder, KNOT_PF_FREE);
- } else {
- /* Return empty answer if name exists, but type doesn't match */
- knot_wire_set_aa(pkt->wire);
- }
- } else {
- ret = kr_error(ENOENT);
- }
- /* Clear RR if failed */
- if (ret != 0) {
- knot_rrset_clear(rr, &pkt->mm);
- }
- return ret;
-}
-
-static int satisfy_reverse(/*const*/ struct hints_data *data,
- knot_pkt_t *pkt, struct kr_query *qry)
-{
- /* Find a matching name */
- pack_t *addr_set = kr_zonecut_find(&data->reverse_hints, qry->sname);
- if (!addr_set || addr_set->len == 0) {
- return kr_error(ENOENT);
- }
- knot_dname_t *qname = knot_dname_copy(qry->sname, &pkt->mm);
- knot_rrset_t rr;
- knot_rrset_init(&rr, qname, KNOT_RRTYPE_PTR, KNOT_CLASS_IN, data->ttl);
-
- /* Append address records from hints */
- uint8_t *addr = pack_last(*addr_set);
- if (addr != NULL) {
- size_t len = pack_obj_len(addr);
- void *addr_val = pack_obj_val(addr);
- knot_rrset_add_rdata(&rr, addr_val, len, &pkt->mm);
- }
-
- return put_answer(pkt, qry, &rr, data->use_nodata);
-}
-
-static int satisfy_forward(/*const*/ struct hints_data *data,
- knot_pkt_t *pkt, struct kr_query *qry)
-{
- /* Find a matching name */
- pack_t *addr_set = kr_zonecut_find(&data->hints, qry->sname);
- if (!addr_set || addr_set->len == 0) {
- return kr_error(ENOENT);
- }
- knot_dname_t *qname = knot_dname_copy(qry->sname, &pkt->mm);
- knot_rrset_t rr;
- knot_rrset_init(&rr, qname, qry->stype, qry->sclass, data->ttl);
-
- size_t family_len;
- switch (rr.type) {
- case KNOT_RRTYPE_A:
- family_len = sizeof(struct in_addr);
- break;
- case KNOT_RRTYPE_AAAA:
- family_len = sizeof(struct in6_addr);
- break;
- default:
- goto finish;
- };
-
- /* Append address records from hints */
- uint8_t *addr = pack_head(*addr_set);
- while (addr != pack_tail(*addr_set)) {
- size_t len = pack_obj_len(addr);
- void *addr_val = pack_obj_val(addr);
- if (len == family_len) {
- knot_rrset_add_rdata(&rr, addr_val, len, &pkt->mm);
- }
- addr = pack_obj_next(addr);
- }
-finish:
- return put_answer(pkt, qry, &rr, data->use_nodata);
-}
-
-static int query(kr_layer_t *ctx, knot_pkt_t *pkt)
-{
- struct kr_query *qry = ctx->req->current_query;
- if (!qry || (ctx->state & KR_STATE_FAIL)) {
- return ctx->state;
- }
-
- struct kr_module *module = ctx->api->data;
- struct hints_data *data = module->data;
- if (!data) { /* No valid file. */
- return ctx->state;
- }
- /* We can optimize for early return like this: */
- if (!data->use_nodata && qry->stype != KNOT_RRTYPE_A
- && qry->stype != KNOT_RRTYPE_AAAA && qry->stype != KNOT_RRTYPE_PTR) {
- return ctx->state;
- }
- /* FIXME: putting directly into packet breaks ordering in case the hint
- * is applied after a CNAME jump. */
- if (knot_dname_in_bailiwick(qry->sname, (const uint8_t *)"\4arpa\0") >= 0) {
- if (satisfy_reverse(data, pkt, qry) != 0)
- return ctx->state;
- } else {
- if (satisfy_forward(data, pkt, qry) != 0)
- return ctx->state;
- }
-
- VERBOSE_MSG(qry, "<= answered from hints\n");
- qry->flags.DNSSEC_WANT = false; /* Never authenticated */
- qry->flags.CACHED = true;
- qry->flags.NO_MINIMIZE = true;
- pkt->parsed = pkt->size;
- knot_wire_set_qr(pkt->wire);
- return KR_STATE_DONE;
-}
-
static int parse_addr_str(union kr_sockaddr *sa, const char *addr)
{
int family = strchr(addr, ':') ? AF_INET6 : AF_INET;
@@ -228,7 +103,7 @@ static const knot_dname_t * addr2reverse(const char *addr)
kr_inaddr_family(&ia.ip));
}
-static int add_pair(struct kr_zonecut *hints, const char *name, const char *addr)
+static int add_pair_root(struct kr_zonecut *hints, const char *name, const char *addr)
{
/* Build key */
knot_dname_t key[KNOT_DNAME_MAXLEN];
@@ -241,73 +116,107 @@ static int add_pair(struct kr_zonecut *hints, const char *name, const char *addr
if (parse_addr_str(&ia, addr) != 0) {
return kr_error(EINVAL);
}
-
return kr_zonecut_add(hints, key, kr_inaddr(&ia.ip), kr_inaddr_len(&ia.ip));
}
-static int add_reverse_pair(struct kr_zonecut *hints, const char *name, const char *addr)
+static int add_pair(const struct hints_data *data, const char *name, const char *addr)
{
- const knot_dname_t *key = addr2reverse(addr);
+ /* Build key */
+ knot_dname_t key[KNOT_DNAME_MAXLEN];
+ if (!knot_dname_from_str(key, name, sizeof(key))) {
+ return kr_error(EINVAL);
+ }
+ knot_dname_to_lower(key);
- if (key == NULL) {
+ union kr_sockaddr ia;
+ if (parse_addr_str(&ia, addr) != 0) {
return kr_error(EINVAL);
}
+ uint16_t rrtype = ia.ip.sa_family == AF_INET6 ? KNOT_RRTYPE_AAAA : KNOT_RRTYPE_A;
+ knot_rrset_t rrs;
+ knot_rrset_init(&rrs, key, rrtype, KNOT_CLASS_IN, data->ttl);
+ int ret;
+ if (ia.ip.sa_family == AF_INET6) {
+ ret = knot_rrset_add_rdata(&rrs, (const uint8_t *)&ia.ip6.sin6_addr, 16, NULL);
+ } else {
+ ret = knot_rrset_add_rdata(&rrs, (const uint8_t *)&ia.ip4.sin_addr, 4, NULL);
+ }
+ if (!ret) ret = kr_rule_local_data_ins(&rrs, NULL, KR_RULE_TAGS_ALL);
+ if (!ret && data->use_nodata) {
+ rrs.type = KNOT_RRTYPE_CNAME;
+ rrs.rrs.count = 0;
+ rrs.rrs.size = 0;
+ ret = kr_rule_local_data_ins(&rrs, NULL, KR_RULE_TAGS_ALL);
+ }
+
+ knot_rdataset_clear(&rrs.rrs, NULL);
+ return ret;
+}
+
+static int add_reverse_pair(const struct hints_data *data, const char *name, const char *addr)
+{
+ const knot_dname_t *key = addr2reverse(addr);
+ if (!key)
+ return kr_error(EINVAL);
+ knot_rrset_t rrs;
+ knot_rrset_init(&rrs, /*const-cast*/(knot_dname_t *)key,
+ KNOT_RRTYPE_PTR, KNOT_CLASS_IN, data->ttl);
knot_dname_t ptr_name[KNOT_DNAME_MAXLEN];
- if (!knot_dname_from_str(ptr_name, name, sizeof(ptr_name))) {
+ if (!knot_dname_from_str(ptr_name, name, sizeof(ptr_name)))
return kr_error(EINVAL);
+ int ret = knot_rrset_add_rdata(&rrs, ptr_name, knot_dname_size(ptr_name), NULL);
+ if (!ret) {
+ ret = kr_rule_local_data_ins(&rrs, NULL, KR_RULE_TAGS_ALL);
+ knot_rdataset_clear(&rrs.rrs, NULL);
}
-
- return kr_zonecut_add(hints, key, ptr_name, knot_dname_size(ptr_name));
+ return ret;
}
-/** For a given name, remove either one address or all of them (if == NULL).
+/** For a given name, remove either one address ##or all of them (if == NULL).
*
* Also remove the corresponding reverse records.
*/
static int del_pair(struct hints_data *data, const char *name, const char *addr)
{
- /* Build key */
- knot_dname_t key[KNOT_DNAME_MAXLEN];
- if (!knot_dname_from_str(key, name, sizeof(key))) {
+ // Parse addr
+ if (!addr)
+ return kr_error(ENOSYS);
+ union kr_sockaddr ia;
+ if (parse_addr_str(&ia, addr) != 0)
return kr_error(EINVAL);
- }
- int key_len = knot_dname_size(key);
-
- if (addr) {
- /* Remove the pair. */
- union kr_sockaddr ia;
- if (parse_addr_str(&ia, addr) != 0) {
- return kr_error(EINVAL);
- }
-
- const knot_dname_t *reverse_key = addr2reverse(addr);
- kr_zonecut_del(&data->reverse_hints, reverse_key, key, key_len);
- return kr_zonecut_del(&data->hints, key,
- kr_inaddr(&ia.ip), kr_inaddr_len(&ia.ip));
- }
- /* We're removing everything for the name;
- * first find the name's pack */
- pack_t *addr_set = kr_zonecut_find(&data->hints, key);
- if (!addr_set || addr_set->len == 0) {
- return kr_error(ENOENT);
- }
-
- /* Remove address records in hints from reverse_hints. */
-
- for (uint8_t *a = pack_head(*addr_set); a != pack_tail(*addr_set);
- a = pack_obj_next(a)) {
- void *addr_val = pack_obj_val(a);
- int family = pack_obj_len(a) == kr_family_len(AF_INET)
- ? AF_INET : AF_INET6;
- const knot_dname_t *reverse_key = raw_addr2reverse(addr_val, family);
- if (reverse_key != NULL) {
- kr_zonecut_del(&data->reverse_hints, reverse_key, key, key_len);
- }
- }
- /* Remove the whole name. */
- return kr_zonecut_del_all(&data->hints, key);
+ // Remove the PTR
+ const knot_dname_t *reverse_key = addr2reverse(addr);
+ knot_rrset_t rrs;
+ knot_rrset_init(&rrs, /*const-cast*/(knot_dname_t *)reverse_key,
+ KNOT_RRTYPE_PTR, KNOT_CLASS_IN, data->ttl);
+ int ret = kr_rule_local_data_del(&rrs, KR_RULE_TAGS_ALL);
+ if (ret != 1)
+ VERBOSE_MSG(NULL, "del_pair PTR for %s; error: %s\n", addr, kr_strerror(ret));
+ if (ret != 1 && ret != kr_error(ENOENT)) // ignore ENOENT for PTR (duplicities)
+ return ret;
+
+ // Remove the forward entry
+ knot_dname_t key_buf[KNOT_DNAME_MAXLEN];
+ rrs.owner = knot_dname_from_str(key_buf, name, sizeof(key_buf));
+ if (!rrs.owner)
+ return kr_error(EINVAL);
+ rrs.type = ia.ip.sa_family == AF_INET6 ? KNOT_RRTYPE_AAAA : KNOT_RRTYPE_A;
+ ret = kr_rule_local_data_del(&rrs, KR_RULE_TAGS_ALL);
+ if (ret != 1)
+ VERBOSE_MSG(NULL, "del_pair for %s; error: %s\n", name, kr_strerror(ret));
+
+ // Remove the NODATA entry; again, not perfect matching,
+ // but we don't care much about this dynamic hints API.
+ if (ret == 1 && data->use_nodata) {
+ rrs.type = KNOT_RRTYPE_CNAME;
+ ret = kr_rule_local_data_del(&rrs, KR_RULE_TAGS_ALL);
+ if (ret != 1)
+ VERBOSE_MSG(NULL, "del_pair for NODATA %s; error: %s\n",
+ name, kr_strerror(ret));
+ }
+ return ret < 0 ? ret : kr_ok();
}
static int load_file(struct kr_module *module, const char *path)
@@ -343,31 +252,21 @@ static int load_file(struct kr_module *module, const char *path)
}
const char *canonical_name = strtok_r(NULL, " \t\n", &saveptr);
if (canonical_name == NULL) {
- ret = -1;
+ ret = kr_error(EINVAL);
goto error;
}
- /* Since the last added PTR records takes preference,
- * we add canonical name as the last one. */
const char *name_tok;
while ((name_tok = strtok_r(NULL, " \t\n", &saveptr)) != NULL) {
- ret = add_pair(&data->hints, name_tok, addr);
- if (!ret) {
- ret = add_reverse_pair(&data->reverse_hints, name_tok, addr);
- }
- if (ret) {
- ret = -1;
+ ret = add_pair(data, name_tok, addr);
+ if (ret)
goto error;
- }
count += 1;
}
- ret = add_pair(&data->hints, canonical_name, addr);
- if (!ret) {
- ret = add_reverse_pair(&data->reverse_hints, canonical_name, addr);
- }
- if (ret) {
- ret = -1;
+ ret = add_pair(data, canonical_name, addr);
+ if (!ret) // PTR only to the canonical name
+ ret = add_reverse_pair(data, canonical_name, addr);
+ if (ret)
goto error;
- }
count += 1;
}
error:
@@ -408,12 +307,9 @@ static char* hint_set(void *env, struct kr_module *module, const char *args)
if (addr) {
*addr = '\0';
++addr;
- ret = add_reverse_pair(&data->reverse_hints, args_copy, addr);
- if (ret) {
- del_pair(data, args_copy, addr);
- } else {
- ret = add_pair(&data->hints, args_copy, addr);
- }
+ ret = add_reverse_pair(data, args_copy, addr);
+ if (!ret)
+ ret = add_pair(data, args_copy, addr);
}
return bool2jsonstr(ret == 0);
@@ -435,6 +331,8 @@ static char* hint_del(void *env, struct kr_module *module, const char *args)
++addr;
}
ret = del_pair(data, args_copy, addr);
+ if (ret)
+ VERBOSE_MSG(NULL, "hints.del(%s) error: %s\n", args, kr_strerror(ret));
return bool2jsonstr(ret == 0);
}
@@ -457,7 +355,6 @@ static JsonNode *pack_addrs(pack_t *pack)
return root;
}
-static char* pack_hints(struct kr_zonecut *hints);
/**
* Retrieve address hints, either for given name or for all names.
*
@@ -466,30 +363,7 @@ static char* pack_hints(struct kr_zonecut *hints);
*/
static char* hint_get(void *env, struct kr_module *module, const char *args)
{
- struct kr_zonecut *hints = &((struct hints_data *) module->data)->hints;
- if (kr_fails_assert(hints))
- return NULL;
-
- if (!args) {
- return pack_hints(hints);
- }
-
- knot_dname_t key[KNOT_DNAME_MAXLEN];
- pack_t *pack = NULL;
- if (knot_dname_from_str(key, args, sizeof(key))) {
- pack = kr_zonecut_find(hints, key);
- }
- if (!pack || pack->len == 0) {
- return NULL;
- }
-
- char *result = NULL;
- JsonNode *root = pack_addrs(pack);
- if (root) {
- result = json_encode(root);
- json_delete(root);
- }
- return result;
+ return NULL;
}
/** @internal Pack all hints into serialized JSON. */
@@ -515,8 +389,12 @@ static void unpack_hint(struct kr_zonecut *root_hints, JsonNode *table, const ch
JsonNode *node = NULL;
json_foreach(node, table) {
switch(node->tag) {
- case JSON_STRING: add_pair(root_hints, name ? name : node->key, node->string_); break;
- case JSON_ARRAY: unpack_hint(root_hints, node, name ? name : node->key); break;
+ case JSON_STRING:
+ add_pair_root(root_hints, name ? name : node->key, node->string_);
+ break;
+ case JSON_ARRAY:
+ unpack_hint(root_hints, node, name ? name : node->key);
+ break;
default: continue;
}
}
@@ -597,14 +475,22 @@ static char* hint_ttl(void *env, struct kr_module *module, const char *args)
KR_EXPORT
int hints_init(struct kr_module *module)
{
- static kr_layer_api_t layer = {
- .produce = &query,
- };
+ static kr_layer_api_t layer = { 0 };
/* Store module reference */
layer.data = module;
module->layer = &layer;
static const struct kr_prop props[] = {
+ /* FIXME(decide): .set() and .del() used to work on individual RRs;
+ * now they overwrite or delete whole RRsets.
+ * Also, .get() doesn't work at all.
+ *
+ * It really depends what kind of config/API we'll be exposing to user.
+ * - Manipulating whole RRsets generally makes more sense to me.
+ * (But hints.set() currently can't even insert larger sets.)
+ * - We'll probably be deprecating access through these non-declarative
+ * commands (set, get, del) which are also usable dynamically.
+ */
{ &hint_set, "set", "Set {name, address} hint.", },
{ &hint_del, "del", "Delete one {name, address} hint or all addresses for the name.", },
{ &hint_get, "get", "Retrieve hint for given name.", },
@@ -617,17 +503,9 @@ int hints_init(struct kr_module *module)
};
module->props = props;
- knot_mm_t *pool = mm_ctx_mempool2(MM_DEFAULT_BLKSIZE);
- if (!pool) {
- return kr_error(ENOMEM);
- }
- struct hints_data *data = mm_alloc(pool, sizeof(struct hints_data));
- if (!data) {
- mp_delete(pool->ctx);
+ struct hints_data *data = malloc(sizeof(*data));
+ if (!data)
return kr_error(ENOMEM);
- }
- kr_zonecut_init(&data->hints, (const uint8_t *)(""), pool);
- kr_zonecut_init(&data->reverse_hints, (const uint8_t *)(""), pool);
data->use_nodata = true;
data->ttl = HINTS_TTL_DEFAULT;
module->data = data;
@@ -639,13 +517,8 @@ int hints_init(struct kr_module *module)
KR_EXPORT
int hints_deinit(struct kr_module *module)
{
- struct hints_data *data = module->data;
- if (data) {
- kr_zonecut_deinit(&data->hints);
- kr_zonecut_deinit(&data->reverse_hints);
- mp_delete(data->hints.pool->ctx);
- module->data = NULL;
- }
+ free(module->data);
+ module->data = NULL;
return kr_ok();
}