diff --git a/lib/zonecut.c b/lib/zonecut.c index 4ec4cdc314298c4784f8509a643b2dbdbfdbc1dc..241485238348aefb926c0561929d7130a6878c35 100644 --- a/lib/zonecut.c +++ b/lib/zonecut.c @@ -267,6 +267,21 @@ int kr_zonecut_del(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rd return ret; } +int kr_zonecut_del_all(struct kr_zonecut *cut, const knot_dname_t *ns) +{ + if (!cut || !ns) { + return kr_error(EINVAL); + } + + /* Find the address list; then free and remove it. */ + pack_t *pack = kr_zonecut_find(cut, ns); + if (pack == NULL) { + return kr_error(ENOENT); + } + free_addr_set((const char *)ns, pack, cut->pool); + return map_del(&cut->nsset, (const char *)ns); +} + pack_t *kr_zonecut_find(struct kr_zonecut *cut, const knot_dname_t *ns) { if (!cut || !ns) { diff --git a/lib/zonecut.h b/lib/zonecut.h index 2395fd2cf4b99a6ee63e711d5c57949a0c08e737..90d7747ae80b093c19beb871b30ce834e3d926eb 100644 --- a/lib/zonecut.h +++ b/lib/zonecut.h @@ -32,7 +32,7 @@ struct kr_zonecut { knot_rrset_t* key; /**< Zone cut DNSKEY. */ knot_rrset_t* trust_anchor; /**< Current trust anchor. */ struct kr_zonecut *parent; /**< Parent zone cut. */ - map_t nsset; /**< Map of nameserver => address_set. */ + map_t nsset; /**< Map of nameserver => address_set. */ knot_mm_t *pool; /**< Memory pool. */ }; @@ -104,6 +104,15 @@ int kr_zonecut_add(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rd KR_EXPORT int kr_zonecut_del(struct kr_zonecut *cut, const knot_dname_t *ns, const knot_rdata_t *rdata); +/** + * Delete all addresses associated with the given name. + * @param cut + * @param ns name server name + * @return 0 or error code + */ +KR_EXPORT +int kr_zonecut_del_all(struct kr_zonecut *cut, const knot_dname_t *ns); + /** * Find nameserver address list in the zone cut. * diff --git a/modules/hints/README.rst b/modules/hints/README.rst index 9a0e7123bd06eab5053a3acb2bd77121ba37f33c..71f2e8eeb7da3b4a50e38487ac6b788589743993 100644 --- a/modules/hints/README.rst +++ b/modules/hints/README.rst @@ -30,7 +30,7 @@ Properties :param string path: path to hosts file, default: ``"/etc/hosts"`` :return: ``{ result: bool }`` - + Load specified hosts file. .. function:: hints.get(hostname) @@ -39,24 +39,32 @@ Properties :return: ``{ result: [address1, address2, ...] }`` Return list of address record matching given name. + If no hostname is specified, all hints are returned in the table format used by ``hints.root()``. .. function:: hints.set(pair) :param string pair: ``hostname address`` i.e. ``"localhost 127.0.0.1"`` :return: ``{ result: bool }`` - Set hostname - address pair hint. + Add a hostname - address pair hint. + +.. function:: hints.del(pair) + + :param string pair: ``hostname address`` i.e. ``"localhost 127.0.0.1"``, or just ``hostname`` + :return: ``{ result: bool }`` + + Remove a hostname - address pair hint. If address is omitted, all addresses for the given name are deleted. .. function:: hints.root() - :return: ``{ ['a.root-servers.net'] = { '1.2.3.4', '5.6.7.8', ...}, ... }`` + :return: ``{ ['a.root-servers.net.'] = { '1.2.3.4', '5.6.7.8', ...}, ... }`` .. tip:: If no parameters are passed, returns current root hints set. .. function:: hints.root(root_hints) :param table root_hints: new set of root hints i.e. ``{['name'] = 'addr', ...}`` - :return: ``{ ['a.root-servers.net'] = { '1.2.3.4', '5.6.7.8', ...}, ... }`` + :return: ``{ ['a.root-servers.net.'] = { '1.2.3.4', '5.6.7.8', ...}, ... }`` Replace current root hints and return the current table of root hints. @@ -76,4 +84,4 @@ Properties } .. tip:: A good rule of thumb is to select only a few fastest root hints. The server learns RTT and NS quality over time, and thus tries all servers available. You can help it by preselecting the candidates. - \ No newline at end of file + diff --git a/modules/hints/hints.c b/modules/hints/hints.c index f7348680dffddfd77f380c476c9c6f42826c3afa..cae6b1532936ea507f27cbed90bc491390572d7c 100644 --- a/modules/hints/hints.c +++ b/modules/hints/hints.c @@ -216,6 +216,22 @@ static int parse_addr_str(struct sockaddr_storage *sa, const char *addr) return 0; } +/** @warning _NOT_ thread-safe; returns a pointer to static data! */ +static const knot_rdata_t * addr2rdata(const char *addr) { + /* Parse address string */ + struct sockaddr_storage ss; + if (parse_addr_str(&ss, addr) != 0) { + return NULL; + } + + /* Build RDATA */ + static knot_rdata_t rdata_arr[RDATA_ARR_MAX]; + size_t addr_len = kr_inaddr_len((struct sockaddr *)&ss); + const uint8_t *raw_addr = (const uint8_t *)kr_inaddr((struct sockaddr *)&ss); + knot_rdata_init(rdata_arr, addr_len, raw_addr, 0); + return rdata_arr; +} + static int add_pair(struct kr_zonecut *hints, const char *name, const char *addr) { /* Build key */ @@ -223,20 +239,34 @@ static int add_pair(struct kr_zonecut *hints, const char *name, const char *addr if (!knot_dname_from_str(key, name, sizeof(key))) { return kr_error(EINVAL); } + const knot_rdata_t *rdata = addr2rdata(addr); + if (!rdata) { + return kr_error(EINVAL); + } - /* Parse address string */ - struct sockaddr_storage ss; - if (parse_addr_str(&ss, addr) != 0) { + return kr_zonecut_add(hints, key, rdata); +} + +/** For a given name, remove either one address or all of them (if == NULL). */ +static int del_pair(struct kr_zonecut *hints, const char *name, const char *addr) +{ + /* Build key */ + knot_dname_t key[KNOT_DNAME_MAXLEN]; + if (!knot_dname_from_str(key, name, sizeof(key))) { return kr_error(EINVAL); } - /* Build RDATA */ - size_t addr_len = kr_inaddr_len((struct sockaddr *)&ss); - const uint8_t *raw_addr = (const uint8_t *)kr_inaddr((struct sockaddr *)&ss); - /* @warning _NOT_ thread-safe */ - static knot_rdata_t rdata_arr[RDATA_ARR_MAX]; - knot_rdata_init(rdata_arr, addr_len, raw_addr, 0); - return kr_zonecut_add(hints, key, rdata_arr); + if (addr) { + /* Remove the pair. */ + const knot_rdata_t *rdata = addr2rdata(addr); + if (!rdata) { + return kr_error(EINVAL); + } + return kr_zonecut_del(hints, key, rdata); + } else { + /* Remove the whole name. */ + return kr_zonecut_del_all(hints, key); + } } static int load_map(struct kr_zonecut *hints, FILE *fp) @@ -327,6 +357,25 @@ static char* hint_set(void *env, struct kr_module *module, const char *args) return result; } +static char* hint_del(void *env, struct kr_module *module, const char *args) +{ + struct kr_zonecut *hints = module->data; + auto_free char *args_copy = strdup(args); + + int ret = -1; + char *addr = strchr(args_copy, ' '); + if (addr) { + *addr = '\0'; + ++addr; + } + ret = del_pair(hints, args_copy, addr); + + char *result = NULL; + if (-1 == asprintf(&result, "{ \"result\": %s }", ret == 0 ? "true" : "false")) + result = NULL; + return result; +} + /** @internal Pack address list into JSON array. */ static JsonNode *pack_addrs(pack_t *pack) { @@ -345,8 +394,9 @@ static JsonNode *pack_addrs(pack_t *pack) return root; } +static char* pack_hints(struct kr_zonecut *hints); /** - * Retrieve address hint for given name. + * Retrieve address hints, either for given name or for all names. * * Input: name * Output: { address1, address2, ... } @@ -354,6 +404,11 @@ static JsonNode *pack_addrs(pack_t *pack) static char* hint_get(void *env, struct kr_module *module, const char *args) { struct kr_zonecut *hints = module->data; + + 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))) { @@ -386,6 +441,17 @@ static int pack_hint(const char *k, void *v, void *baton) return kr_ok(); } +/** @internal Pack all hints into serialized JSON. */ +static char* pack_hints(struct kr_zonecut *hints) { + char *result = NULL; + JsonNode *root_node = json_mkobject(); + if (map_walk(&hints->nsset, pack_hint, root_node) == 0) { + result = json_encode(root_node); + } + json_delete(root_node); + return result; +} + static void unpack_hint(struct kr_zonecut *root_hints, JsonNode *table, const char *name) { JsonNode *node = NULL; @@ -418,13 +484,7 @@ static char* hint_root(void *env, struct kr_module *module, const char *args) json_delete(root_node); } /* Return current root hints */ - char *result = NULL; - JsonNode *root_node = json_mkobject(); - if (map_walk(&root_hints->nsset, pack_hint, root_node) == 0) { - result = json_encode(root_node); - } - json_delete(root_node); - return result; + return pack_hints(root_hints); } /* @@ -471,6 +531,7 @@ struct kr_prop *hints_props(void) { static struct kr_prop prop_list[] = { { &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.", }, { &hint_root, "root", "Replace root hints set (empty value to return current list).", }, { NULL, NULL, NULL }