]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
hints: allow removing hints
authorVladimír Čunát <vladimir.cunat@nic.cz>
Tue, 29 Nov 2016 14:07:48 +0000 (15:07 +0100)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Tue, 29 Nov 2016 14:07:48 +0000 (15:07 +0100)
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".

lib/zonecut.c
lib/zonecut.h
modules/hints/README.rst
modules/hints/hints.c

index 4ec4cdc314298c4784f8509a643b2dbdbfdbc1dc..241485238348aefb926c0561929d7130a6878c35 100644 (file)
@@ -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) {
index 2395fd2cf4b99a6ee63e711d5c57949a0c08e737..98432a571fa5c524cc2787bbd9ac8ce7cb191831 100644 (file)
@@ -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.
  *
index 9a0e7123bd06eab5053a3acb2bd77121ba37f33c..e96c74b34cde73390c545483d65792ab4c301b1a 100644 (file)
@@ -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
+
index f7348680dffddfd77f380c476c9c6f42826c3afa..28341138cdcd8c59beeebeb1b9c1838680297399 100644 (file)
@@ -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 }