]> git.ipfire.org Git - thirdparty/knot-resolver.git/commitdiff
hints: expose as C kr_rule_local_*()
authorVladimír Čunát <vladimir.cunat@nic.cz>
Fri, 18 Aug 2023 17:13:12 +0000 (19:13 +0200)
committerVladimír Čunát <vladimir.cunat@nic.cz>
Tue, 12 Sep 2023 10:12:55 +0000 (12:12 +0200)
At least the normal non-root hints.
We needed extended API for this functionality, and C API is simpler
for this, thanks to LuaJIT FFI.

However, this required moving code from the separate module.
The moved code is not changed in any way in this commit.
I considered it bad to keep such core code outside the main daemon+lib,
as it's not big.  Now LuaJIT FFI forced me to clean this up.

daemon/lua/kres-gen-30.lua
daemon/lua/kres-gen-31.lua
daemon/lua/kres-gen-32.lua
daemon/lua/kres-gen.sh
daemon/main.c
lib/meson.build
lib/rules/api.h
lib/rules/local-addr.c [new file with mode: 0644]
modules/hints/hints.c

index 763183899503562844cb0b68db84910330c03a37..9d2d846e22511ee8401dc27ba099f480b5461e06 100644 (file)
@@ -498,6 +498,8 @@ int kr_rule_local_data_emptyzone(const knot_dname_t *, kr_rule_tags_t);
 int kr_rule_local_data_nxdomain(const knot_dname_t *, kr_rule_tags_t);
 int kr_rule_zonefile(const struct kr_rule_zonefile_config *);
 int kr_rule_forward(const knot_dname_t *, kr_rule_fwd_flags_t, const struct sockaddr **);
+int kr_rule_local_address(const char *, const char *, _Bool, uint32_t, kr_rule_tags_t);
+int kr_rule_local_hosts(const char *, _Bool, uint32_t, kr_rule_tags_t);
 typedef struct {
        int sock_type;
        _Bool tls;
index 1e9e1e3d35b61406c989e945bf44a5ee26d3dcd5..f10049301b92d8ef62ad31f91b8b6671fbf92156 100644 (file)
@@ -498,6 +498,8 @@ int kr_rule_local_data_emptyzone(const knot_dname_t *, kr_rule_tags_t);
 int kr_rule_local_data_nxdomain(const knot_dname_t *, kr_rule_tags_t);
 int kr_rule_zonefile(const struct kr_rule_zonefile_config *);
 int kr_rule_forward(const knot_dname_t *, kr_rule_fwd_flags_t, const struct sockaddr **);
+int kr_rule_local_address(const char *, const char *, _Bool, uint32_t, kr_rule_tags_t);
+int kr_rule_local_hosts(const char *, _Bool, uint32_t, kr_rule_tags_t);
 typedef struct {
        int sock_type;
        _Bool tls;
index cc37af74d5ea7204431ce3ac15a2636107814d92..993b092c1d8199721f140f1890d6998177782ced 100644 (file)
@@ -499,6 +499,8 @@ int kr_rule_local_data_emptyzone(const knot_dname_t *, kr_rule_tags_t);
 int kr_rule_local_data_nxdomain(const knot_dname_t *, kr_rule_tags_t);
 int kr_rule_zonefile(const struct kr_rule_zonefile_config *);
 int kr_rule_forward(const knot_dname_t *, kr_rule_fwd_flags_t, const struct sockaddr **);
+int kr_rule_local_address(const char *, const char *, _Bool, uint32_t, kr_rule_tags_t);
+int kr_rule_local_hosts(const char *, _Bool, uint32_t, kr_rule_tags_t);
 typedef struct {
        int sock_type;
        _Bool tls;
index 00dae4ff0a010c1977374dc43f3a1198370c70bb..0672dbcc8922373f977fbe9e003883c710f02b76 100755 (executable)
@@ -297,6 +297,8 @@ ${CDEFS} ${LIBKRES} functions <<-EOF
        kr_rule_local_data_nxdomain
        kr_rule_zonefile
        kr_rule_forward
+       kr_rule_local_address
+       kr_rule_local_hosts
 EOF
 
 
index efbe8e55aa0e524cfa6070d820a3942e427ac089..53ecb3e8f93cd74c905d654c7c86b16bb0d32c14 100644 (file)
@@ -71,10 +71,11 @@ KR_EXPORT const char *malloc_conf = "narenas:1";
 #define TCP_BACKLOG_DEFAULT 128
 #endif
 
-/** I don't know why linker is dropping this _zonefile function otherwise. TODO: revisit. */
+/** I don't know why linker is dropping these functions otherwise. TODO: revisit. */
 KR_EXPORT void kr_misc_unused(void)
 {
        kr_rule_zonefile(NULL);
+       kr_rule_local_address(NULL, NULL, false, 0, 0);
 }
 
 struct args the_args_value;  /** Static allocation for the_args singleton. */
index 48185e170d7413f58efd13e862f2af7bba3504dc..d8cbf1fad77123a9439811e1956611f639048c75 100644 (file)
@@ -26,6 +26,7 @@ libkres_src = files([
   'rules/api.c',
   'rules/defaults.c',
   'rules/forward.c',
+  'rules/local-addr.c',
   'rules/zonefile.c',
   'module.c',
   'resolve.c',
index e4995582c31647f65f49104a7c1e654bba1d0210..d791d2966f3128f21028e27f58369750c552fc9a 100644 (file)
@@ -80,6 +80,32 @@ int kr_rule_local_data_ins(const knot_rrset_t *rrs, const knot_rdataset_t *sig_r
 KR_EXPORT
 int kr_rule_local_data_merge(const knot_rrset_t *rrs, kr_rule_tags_t tags);
 
+/** Add a name-address pair into rules.
+ *
+ * - both forward and reverse mapping is added
+ * - merging is used; see kr_rule_local_data_merge()
+ * - NODATA is optionally inserted
+ */
+KR_EXPORT
+int kr_rule_local_address(const char *name, const char *addr,
+                               bool use_nodata, uint32_t ttl, kr_rule_tags_t tags);
+
+/** For a given name, remove one address  ##or all of them (if == NULL).
+ *
+ * Also remove the corresponding reverse record and (optionally) NODATA mark.
+ * Bug: it removes the whole forward RRset.
+ */
+KR_EXPORT
+int kr_rule_local_address_del(const char *name, const char *addr,
+                               bool use_nodata, kr_rule_tags_t tags);
+
+/** Load name-address pairs into rules from a hosts-like file.
+ *
+ * Same as kr_rule_data_address() but from a file.
+ */
+KR_EXPORT
+int kr_rule_local_hosts(const char *path, bool use_nodata, uint32_t ttl, kr_rule_tags_t tags);
+
 /** Remove a local data rule.
  *
  * \return the number of deleted rules or error < 0
diff --git a/lib/rules/local-addr.c b/lib/rules/local-addr.c
new file mode 100644 (file)
index 0000000..787639d
--- /dev/null
@@ -0,0 +1,236 @@
+/*  Copyright (C) CZ.NIC, z.s.p.o. <knot-resolver@labs.nic.cz>
+ *  SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "lib/rules/api.h"
+#include "lib/rules/impl.h"
+
+#include "contrib/cleanup.h"
+
+#include <stdio.h>
+
+static int parse_addr_str(union kr_sockaddr *sa, const char *addr)
+{
+       int family = strchr(addr, ':') ? AF_INET6 : AF_INET;
+       memset(sa, 0, sizeof(*sa));
+       sa->ip.sa_family = family;
+       char *addr_bytes = (/*const*/char *)kr_inaddr(&sa->ip);
+       if (inet_pton(family, addr, addr_bytes) != 1) {
+               return kr_error(EILSEQ);
+       }
+       return 0;
+}
+
+static int add_pair(const char *name, const char *addr,
+                       bool use_nodata, uint32_t ttl, kr_rule_tags_t tags)
+{
+       /* 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);
+
+       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, 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_merge(&rrs, tags);
+       if (!ret && use_nodata) {
+               rrs.type = KNOT_RRTYPE_CNAME;
+               rrs.rrs.count = 0;
+               rrs.rrs.size = 0;
+               // no point in the _merge() variant here
+               ret = kr_rule_local_data_ins(&rrs, NULL, tags);
+       }
+
+       knot_rdataset_clear(&rrs.rrs, NULL);
+       return ret;
+}
+
+/** @warning _NOT_ thread-safe; returns a pointer to static data! */
+static const knot_dname_t * raw_addr2reverse(const uint8_t *raw_addr, int family)
+{
+       #define REV_MAXLEN (4*16 + 16 /* the suffix, terminator, etc. */)
+       char reverse_addr[REV_MAXLEN];
+       static knot_dname_t dname[REV_MAXLEN];
+       #undef REV_MAXLEN
+
+       if (family == AF_INET) {
+               snprintf(reverse_addr, sizeof(reverse_addr),
+                        "%d.%d.%d.%d.in-addr.arpa.",
+                        raw_addr[3], raw_addr[2], raw_addr[1], raw_addr[0]);
+       } else if (family == AF_INET6) {
+               char *ra_it = reverse_addr;
+               for (int i = 15; i >= 0; --i) {
+                       ssize_t free_space = reverse_addr + sizeof(reverse_addr) - ra_it;
+                       int written = snprintf(ra_it, free_space, "%x.%x.",
+                                               raw_addr[i] & 0x0f, raw_addr[i] >> 4);
+                       if (kr_fails_assert(written < free_space))
+                               return NULL;
+                       ra_it += written;
+               }
+               ssize_t free_space = reverse_addr + sizeof(reverse_addr) - ra_it;
+               if (snprintf(ra_it, free_space, "ip6.arpa.") >= free_space) {
+                       return NULL;
+               }
+       } else {
+               return NULL;
+       }
+
+       if (!knot_dname_from_str(dname, reverse_addr, sizeof(dname))) {
+               return NULL;
+       }
+       return dname;
+}
+static const knot_dname_t * addr2reverse(const char *addr)
+{
+       /* Parse address string */
+       union kr_sockaddr ia;
+       if (parse_addr_str(&ia, addr) != 0) {
+               return NULL;
+       }
+       return raw_addr2reverse((const /*sign*/uint8_t *)kr_inaddr(&ia.ip),
+                               kr_inaddr_family(&ia.ip));
+}
+
+static int add_reverse_pair(const char *name, const char *addr,
+                       bool use_nodata, uint32_t ttl, kr_rule_tags_t tags)
+{
+       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, ttl);
+       knot_dname_t ptr_name[KNOT_DNAME_MAXLEN];
+       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) {
+               // We use _merge().  Using multiple PTR RRs is not recommended generally,
+               // but here it seems better than choosing any "arbitrarily".
+               ret = kr_rule_local_data_merge(&rrs, tags);
+               knot_rdataset_clear(&rrs.rrs, NULL);
+       }
+       return ret;
+}
+
+int kr_rule_local_address(const char *name, const char *addr,
+                               bool use_nodata, uint32_t ttl, kr_rule_tags_t tags)
+{
+       int ret = add_reverse_pair(name, addr, use_nodata, ttl, tags);
+       if (ret) return ret;
+       return add_pair(name, addr, use_nodata, ttl, tags);
+}
+
+int kr_rule_local_address_del(const char *name, const char *addr,
+                               bool use_nodata, kr_rule_tags_t tags)
+{
+       // Parse addr
+       if (!addr)
+               return kr_error(ENOSYS);
+       union kr_sockaddr ia;
+       if (parse_addr_str(&ia, addr) != 0)
+               return kr_error(EINVAL);
+
+       // 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, 0);
+       int ret = kr_rule_local_data_del(&rrs, tags);
+       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, tags);
+       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 && use_nodata) {
+               rrs.type = KNOT_RRTYPE_CNAME;
+               ret = kr_rule_local_data_del(&rrs, tags);
+               if (ret != 1)
+                       VERBOSE_MSG(NULL, "del_pair for NODATA %s; error: %s\n",
+                                       name, kr_strerror(ret));
+       }
+       return ret < 0 ? ret : kr_ok();
+}
+
+int kr_rule_local_hosts(const char *path, bool use_nodata, uint32_t ttl, kr_rule_tags_t tags)
+{
+       auto_fclose FILE *fp = fopen(path, "r");
+       if (fp == NULL) {
+               kr_log_error(RULES, "reading '%s' failed: %s\n", path, strerror(errno));
+               return kr_error(errno);
+       } else {
+               VERBOSE_MSG(NULL, "reading '%s'\n", path);
+       }
+
+       /* Load file to map */
+       size_t line_len_unused = 0;
+       size_t count = 0;
+       size_t line_count = 0;
+       auto_free char *line = NULL;
+       int ret = kr_ok();
+
+       while (getline(&line, &line_len_unused, fp) > 0) {
+               ++line_count;
+               /* Ingore #comments as described in man hosts.5 */
+               char *comm = strchr(line, '#');
+               if (comm) {
+                       *comm = '\0';
+               }
+
+               char *saveptr = NULL;
+               const char *addr = strtok_r(line, " \t\n", &saveptr);
+               if (addr == NULL || strlen(addr) == 0) {
+                       continue;
+               }
+               const char *canonical_name = strtok_r(NULL, " \t\n", &saveptr);
+               if (canonical_name == NULL) {
+                       ret = kr_error(EINVAL);
+                       goto error;
+               }
+               const char *name_tok;
+               while ((name_tok = strtok_r(NULL, " \t\n", &saveptr)) != NULL) {
+                       ret = add_pair(name_tok, addr, use_nodata, ttl, tags);
+                       if (ret)
+                               goto error;
+                       count += 1;
+               }
+               ret = add_pair(canonical_name, addr, use_nodata, ttl, tags);
+               if (!ret) // PTR only to the canonical name
+                       ret = add_reverse_pair(canonical_name, addr, use_nodata, ttl, tags);
+               if (ret)
+                       goto error;
+               count += 1;
+       }
+error:
+       if (ret) {
+               ret = kr_error(ret);
+               kr_log_error(RULES, "%s:%zu: invalid syntax\n", path, line_count);
+       }
+       VERBOSE_MSG(NULL, "loaded %zu hints\n", count);
+       return ret;
+}
index 1326938f98ed49b9db43b0a5a8457618525a1490..c422bce0bf1d8cea7be450b858c2f3b4ead1a9bc 100644 (file)
@@ -56,53 +56,6 @@ static int parse_addr_str(union kr_sockaddr *sa, const char *addr)
        return 0;
 }
 
-/** @warning _NOT_ thread-safe; returns a pointer to static data! */
-static const knot_dname_t * raw_addr2reverse(const uint8_t *raw_addr, int family)
-{
-       #define REV_MAXLEN (4*16 + 16 /* the suffix, terminator, etc. */)
-       char reverse_addr[REV_MAXLEN];
-       static knot_dname_t dname[REV_MAXLEN];
-       #undef REV_MAXLEN
-
-       if (family == AF_INET) {
-               snprintf(reverse_addr, sizeof(reverse_addr),
-                        "%d.%d.%d.%d.in-addr.arpa.",
-                        raw_addr[3], raw_addr[2], raw_addr[1], raw_addr[0]);
-       } else if (family == AF_INET6) {
-               char *ra_it = reverse_addr;
-               for (int i = 15; i >= 0; --i) {
-                       ssize_t free_space = reverse_addr + sizeof(reverse_addr) - ra_it;
-                       int written = snprintf(ra_it, free_space, "%x.%x.",
-                                               raw_addr[i] & 0x0f, raw_addr[i] >> 4);
-                       if (kr_fails_assert(written < free_space))
-                               return NULL;
-                       ra_it += written;
-               }
-               ssize_t free_space = reverse_addr + sizeof(reverse_addr) - ra_it;
-               if (snprintf(ra_it, free_space, "ip6.arpa.") >= free_space) {
-                       return NULL;
-               }
-       } else {
-               return NULL;
-       }
-
-       if (!knot_dname_from_str(dname, reverse_addr, sizeof(dname))) {
-               return NULL;
-       }
-       return dname;
-}
-
-static const knot_dname_t * addr2reverse(const char *addr)
-{
-       /* Parse address string */
-       union kr_sockaddr ia;
-       if (parse_addr_str(&ia, addr) != 0) {
-               return NULL;
-       }
-       return raw_addr2reverse((const /*sign*/uint8_t *)kr_inaddr(&ia.ip),
-                               kr_inaddr_family(&ia.ip));
-}
-
 static int add_pair_root(struct kr_zonecut *hints, const char *name, const char *addr)
 {
        /* Build key */
@@ -119,171 +72,6 @@ static int add_pair_root(struct kr_zonecut *hints, const char *name, const char
        return kr_zonecut_add(hints, key, kr_inaddr(&ia.ip), kr_inaddr_len(&ia.ip));
 }
 
-static int add_pair(const char *name, const char *addr,
-                       bool use_nodata, uint32_t ttl, kr_rule_tags_t tags)
-{
-       /* 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);
-
-       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, 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_merge(&rrs, tags);
-       if (!ret && use_nodata) {
-               rrs.type = KNOT_RRTYPE_CNAME;
-               rrs.rrs.count = 0;
-               rrs.rrs.size = 0;
-               // no point in the _merge() variant here
-               ret = kr_rule_local_data_ins(&rrs, NULL, tags);
-       }
-
-       knot_rdataset_clear(&rrs.rrs, NULL);
-       return ret;
-}
-
-static int add_reverse_pair(const char *name, const char *addr,
-                       bool use_nodata, uint32_t ttl, kr_rule_tags_t tags)
-{
-       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, ttl);
-       knot_dname_t ptr_name[KNOT_DNAME_MAXLEN];
-       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) {
-               // We use _merge().  Using multiple PTR RRs is not recommended generally,
-               // but here it seems better than choosing any "arbitrarily".
-               ret = kr_rule_local_data_merge(&rrs, tags);
-               knot_rdataset_clear(&rrs.rrs, NULL);
-       }
-       return ret;
-}
-
-/** For a given name, remove either one address  ##or all of them (if == NULL).
- *
- * Also remove the corresponding reverse records.
- * Bug: it removes the whole forward RRset.
- */
-int kr_rule_local_address_del(const char *name, const char *addr,
-                               bool use_nodata, kr_rule_tags_t tags)
-{
-       // Parse addr
-       if (!addr)
-               return kr_error(ENOSYS);
-       union kr_sockaddr ia;
-       if (parse_addr_str(&ia, addr) != 0)
-               return kr_error(EINVAL);
-
-       // 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, 0);
-       int ret = kr_rule_local_data_del(&rrs, tags);
-       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, tags);
-       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 && use_nodata) {
-               rrs.type = KNOT_RRTYPE_CNAME;
-               ret = kr_rule_local_data_del(&rrs, tags);
-               if (ret != 1)
-                       VERBOSE_MSG(NULL, "del_pair for NODATA %s; error: %s\n",
-                                       name, kr_strerror(ret));
-       }
-       return ret < 0 ? ret : kr_ok();
-}
-
-int kr_rule_local_hosts(const char *path, bool use_nodata, uint32_t ttl, kr_rule_tags_t tags)
-{
-       auto_fclose FILE *fp = fopen(path, "r");
-       if (fp == NULL) {
-               ERR_MSG("reading '%s' failed: %s\n", path, strerror(errno));
-               return kr_error(errno);
-       } else {
-               VERBOSE_MSG(NULL, "reading '%s'\n", path);
-       }
-
-       /* Load file to map */
-       size_t line_len_unused = 0;
-       size_t count = 0;
-       size_t line_count = 0;
-       auto_free char *line = NULL;
-       int ret = kr_ok();
-
-       while (getline(&line, &line_len_unused, fp) > 0) {
-               ++line_count;
-               /* Ingore #comments as described in man hosts.5 */
-               char *comm = strchr(line, '#');
-               if (comm) {
-                       *comm = '\0';
-               }
-
-               char *saveptr = NULL;
-               const char *addr = strtok_r(line, " \t\n", &saveptr);
-               if (addr == NULL || strlen(addr) == 0) {
-                       continue;
-               }
-               const char *canonical_name = strtok_r(NULL, " \t\n", &saveptr);
-               if (canonical_name == NULL) {
-                       ret = kr_error(EINVAL);
-                       goto error;
-               }
-               const char *name_tok;
-               while ((name_tok = strtok_r(NULL, " \t\n", &saveptr)) != NULL) {
-                       ret = add_pair(name_tok, addr, use_nodata, ttl, tags);
-                       if (ret)
-                               goto error;
-                       count += 1;
-               }
-               ret = add_pair(canonical_name, addr, use_nodata, ttl, tags);
-               if (!ret) // PTR only to the canonical name
-                       ret = add_reverse_pair(canonical_name, addr, use_nodata, ttl, tags);
-               if (ret)
-                       goto error;
-               count += 1;
-       }
-error:
-       if (ret) {
-               ret = kr_error(ret);
-               ERR_MSG("%s:%zu: invalid syntax\n", path, line_count);
-       }
-       VERBOSE_MSG(NULL, "loaded %zu hints\n", count);
-       return ret;
-}
-
 static char* hint_add_hosts(void *env, struct kr_module *module, const char *args)
 {
        if (!args)
@@ -293,13 +81,6 @@ static char* hint_add_hosts(void *env, struct kr_module *module, const char *arg
        return bool2jsonstr(err == kr_ok());
 }
 
-int kr_rule_local_address(const char *name, const char *addr,
-                               bool use_nodata, uint32_t ttl, kr_rule_tags_t tags)
-{
-       int ret = add_reverse_pair(name, addr, use_nodata, ttl, KR_RULE_TAGS_ALL);
-       if (ret) return ret;
-       return add_pair(name, addr, use_nodata, ttl, KR_RULE_TAGS_ALL);
-}
 /**
  * Set name => address hint.
  *