From: Vladimír Čunát Date: Tue, 29 Nov 2016 14:07:48 +0000 (+0100) Subject: hints: allow removing hints X-Git-Tag: v1.2.0-rc1~67^2~1 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=4080d6d5c3ce62fa19afc885ea1f0310d5ec98df;p=thirdparty%2Fknot-resolver.git hints: allow removing hints Fixes #111. Compatibility: it needs a new libkres.so function. If a wrong version combination is attempted, the module just cleanly fails to load, though it writes a slightly confusing message "no such file or directory". --- diff --git a/lib/zonecut.c b/lib/zonecut.c index 4ec4cdc31..241485238 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 2395fd2cf..98432a571 100644 --- a/lib/zonecut.h +++ b/lib/zonecut.h @@ -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 9a0e7123b..e96c74b34 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) @@ -45,7 +45,14 @@ Properties :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() @@ -76,4 +83,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 f7348680d..28341138c 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) { @@ -471,6 +520,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 }