summaryrefslogtreecommitdiff
path: root/src/libs6dns
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2023-07-03 18:57:42 +0000
committerLaurent Bercot <ska@appnovation.com>2023-07-03 18:57:42 +0000
commit5dc54a39e47148803d950d2facb42500e08f4769 (patch)
tree7875d1088c002ae64b7fc962ba013e948515f1c1 /src/libs6dns
parenta02a1c5608a47211b3e672c8834a8e8a2f917ce6 (diff)
downloads6-dns-5dc54a39e47148803d950d2facb42500e08f4769.tar.xz
Add s6-dns-hosts-compile, prepare for 2.3.6.0
Signed-off-by: Laurent Bercot <ska@appnovation.com>
Diffstat (limited to 'src/libs6dns')
-rw-r--r--src/libs6dns/deps-lib/s6dns1
-rw-r--r--src/libs6dns/s6dns_hosts_compile.c357
-rw-r--r--src/libs6dns/s6dns_hosts_compile.txt31
-rw-r--r--src/libs6dns/s6dns_hosts_here.c7
-rw-r--r--src/libs6dns/s6dns_hosts_init.c62
5 files changed, 458 insertions, 0 deletions
diff --git a/src/libs6dns/deps-lib/s6dns b/src/libs6dns/deps-lib/s6dns
index fd74385..7ade4f4 100644
--- a/src/libs6dns/deps-lib/s6dns
+++ b/src/libs6dns/deps-lib/s6dns
@@ -24,6 +24,7 @@ s6dns_fmt_mx.o
s6dns_fmt_soa.o
s6dns_fmt_srv.o
s6dns_fmt_caa.o
+s6dns_hosts_compile.o
s6dns_message_counts_next.o
s6dns_message_counts_pack.o
s6dns_message_counts_unpack.o
diff --git a/src/libs6dns/s6dns_hosts_compile.c b/src/libs6dns/s6dns_hosts_compile.c
new file mode 100644
index 0000000..20da86f
--- /dev/null
+++ b/src/libs6dns/s6dns_hosts_compile.c
@@ -0,0 +1,357 @@
+/* ISC license. */
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <sys/uio.h>
+
+#include <skalibs/buffer.h>
+#include <skalibs/fmtscan.h>
+#include <skalibs/cdbmake.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/avltree.h>
+
+#include <s6-dns/hosts.h>
+
+
+ /* Definitions */
+
+typedef struct node_name_s node_name, *node_name_ref ;
+struct node_name_s
+{
+ size_t pos ;
+ stralloc ipv4 ;
+ stralloc ipv6 ;
+} ;
+
+typedef struct node_ip_s node_ip, *node_ip_ref ;
+struct node_ip_s
+{
+ char addr[16] ;
+ genalloc names ; /* size_t */
+} ;
+
+typedef struct hostdata_s hostdata, *hostdata_ref ;
+struct hostdata_s
+{
+ stralloc storage ;
+ gensetdyn alias ;
+ gensetdyn fqdn ;
+ gensetdyn ipv4 ;
+ gensetdyn ipv6 ;
+ avltree byalias ;
+ avltree byfqdn ;
+ avltree byipv4 ;
+ avltree byipv6 ;
+} ;
+#define HOSTDATA_ZERO \
+{ \
+ .storage = STRALLOC_ZERO, \
+ .alias = GENSETDYN_INIT(node_name, 3, 3, 8), \
+ .fqdn = GENSETDYN_INIT(node_name, 3, 3, 8), \
+ .ipv4 = GENSETDYN_INIT(node_ip, 3, 3, 8), \
+ .ipv6 = GENSETDYN_INIT(node_ip, 3, 3, 8), \
+ .byalias = AVLTREE_ZERO, \
+ .byfqdn = AVLTREE_ZERO, \
+ .byipv4 = AVLTREE_ZERO, \
+ .byipv6 = AVLTREE_ZERO \
+}
+
+typedef struct hdcm_s hdcm, *hdcm_ref ;
+struct hdcm_s
+{
+ hostdata *hd ;
+ cdbmaker *cm ;
+ char key[2] ;
+} ;
+
+
+ /* Utility */
+
+static void node_name_free (void *data)
+{
+ node_name *node = data ;
+ stralloc_free(&node->ipv4) ;
+ stralloc_free(&node->ipv6) ;
+}
+
+static void node_ip_free (void *data)
+{
+ node_ip *node = data ;
+ genalloc_free(size_t, &node->names) ;
+}
+
+static void hostdata_free (hostdata *hd)
+{
+ gensetdyn_deepfree(&hd->alias, &node_name_free) ;
+ gensetdyn_deepfree(&hd->fqdn, &node_name_free) ;
+ gensetdyn_deepfree(&hd->ipv4, &node_ip_free) ;
+ gensetdyn_deepfree(&hd->ipv6, &node_ip_free) ;
+ avltree_free(&hd->byalias) ;
+ avltree_free(&hd->byfqdn) ;
+ avltree_free(&hd->byipv4) ;
+ avltree_free(&hd->byipv6) ;
+ stralloc_free(&hd->storage) ;
+}
+
+static int name_cmp (void const *a, void const *b, void *aux)
+{
+ (void)aux ;
+ return strcmp((char const *)a, (char const *)b) ;
+}
+
+static void *byalias_dtok (uint32_t d, void *aux)
+{
+ hostdata *hd = aux ;
+ return hd->storage.s + GENSETDYN_P(node_name, &hd->alias, d)->pos ;
+}
+
+static void *byfqdn_dtok (uint32_t d, void *aux)
+{
+ hostdata *hd = aux ;
+ return hd->storage.s + GENSETDYN_P(node_name, &hd->fqdn, d)->pos ;
+}
+
+static int ipv4_cmp (void const *a, void const *b, void *aux)
+{
+ (void)aux ;
+ return memcmp((char const *)a, (char const *)b, 4) ;
+}
+
+static void *byipv4_dtok (uint32_t d, void *aux)
+{
+ hostdata *hd = aux ;
+ return GENSETDYN_P(node_ip, &hd->ipv4, d)->addr ;
+}
+
+static int ipv6_cmp (void const *a, void const *b, void *aux)
+{
+ (void)aux ;
+ return memcmp((char const *)a, (char const *)b, 16) ;
+}
+
+static void *byipv6_dtok (uint32_t d, void *aux)
+{
+ hostdata *hd = aux ;
+ return GENSETDYN_P(node_ip, &hd->ipv6, d)->addr ;
+}
+
+
+ /* Reading */
+
+static inline uint8_t cclass (char c)
+{
+ static uint8_t const ctable[128] = "09999999913111999999999999999999199999999999945977777777776999999888888888888888888888888889999898888888888888888888888888899999" ;
+ return c < 0 ? 9 : ctable[(uint8_t)c] - '0' ;
+}
+
+static inline char next (buffer *b)
+{
+ char c ;
+ return buffer_get(b, &c, 1) <= 0 ? 0 : c ;
+}
+
+static int s6dns_hosts_parse (buffer *b, hostdata *hd)
+{
+ static uint8_t const table[6][10] =
+ {
+ { 0x06, 0x00, 0x01, 0x00, 0x07, 0x07, 0x0a, 0x0a, 0x0a, 0x07 },
+ { 0x06, 0x01, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01 },
+ { 0x16, 0x13, 0x07, 0x10, 0x07, 0x0a, 0x0a, 0x0a, 0x0a, 0x07 },
+ { 0x06, 0x03, 0x01, 0x00, 0x07, 0x07, 0x07, 0x07, 0x0c, 0x07 },
+ { 0x26, 0x64, 0x07, 0x20, 0x0c, 0x0c, 0x07, 0x0c, 0x0c, 0x07 },
+ { 0x06, 0x05, 0x01, 0x00, 0x07, 0x07, 0x07, 0x07, 0x0c, 0x07 }
+ } ;
+ node_ip *node = 0 ;
+ size_t mark = hd->storage.len ;
+ uint8_t flags = 0 ;
+ uint8_t state = 0 ;
+ while (state < 0x06)
+ {
+ uint8_t c ;
+ char cur ;
+ ssize_t r = buffer_get(b, &cur, 1) ;
+ if (r == -1) goto err ;
+ if (!r) cur = 0 ;
+ c = table[state][cclass(cur)] ;
+ state = c & 0x07 ;
+ if (c & 0x08) if (!stralloc_catb(&hd->storage, &cur, 1)) goto err ;
+ if (c & 0x10)
+ {
+ char ip[16] ;
+ if (!stralloc_0(&hd->storage)) goto err ;
+ if (ip6_scan(hd->storage.s + mark, ip))
+ {
+ uint32_t d ;
+ if (!avltree_search(&hd->byipv6, ip, &d))
+ {
+ if (!gensetdyn_new(&hd->ipv6, &d)) goto err ;
+ memcpy(GENSETDYN_P(node_ip, &hd->ipv6, d)->addr, ip, 16) ;
+ GENSETDYN_P(node_ip, &hd->ipv6, d)->names = genalloc_zero ;
+ if (!avltree_insert(&hd->byipv6, d)) goto err ;
+ }
+ flags |= 1 ;
+ node = GENSETDYN_P(node_ip, &hd->ipv6, d) ;
+ }
+ else if (ip4_scan(hd->storage.s + mark, ip))
+ {
+ uint32_t d ;
+ if (!avltree_search(&hd->byipv4, ip, &d))
+ {
+ if (!gensetdyn_new(&hd->ipv4, &d)) goto err ;
+ memcpy(GENSETDYN_P(node_ip, &hd->ipv4, d)->addr, ip, 4) ;
+ GENSETDYN_P(node_ip, &hd->ipv4, d)->names = genalloc_zero ;
+ if (!avltree_insert(&hd->byipv4, d)) goto err ;
+ }
+ flags &= ~1 ;
+ node = GENSETDYN_P(node_ip, &hd->ipv4, d) ;
+ }
+ else goto err ;
+ hd->storage.len = mark ;
+ flags &= ~2 ;
+ }
+ if (c & 0x20)
+ {
+ node_name *noden ;
+ size_t i = 0 ;
+ if (flags & 2)
+ {
+ uint32_t d ;
+ if (!stralloc_0(&hd->storage)) goto err ;
+ if (!avltree_search(&hd->byalias, hd->storage.s + mark, &d))
+ {
+ if (!gensetdyn_new(&hd->alias, &d)) goto err ;
+ GENSETDYN_P(node_name, &hd->alias, d)->pos = mark ;
+ GENSETDYN_P(node_name, &hd->alias, d)->ipv4 = stralloc_zero ;
+ GENSETDYN_P(node_name, &hd->alias, d)->ipv6 = stralloc_zero ;
+ if (!avltree_insert(&hd->byalias, d)) goto err ;
+ }
+ else hd->storage.len = mark ;
+ noden = GENSETDYN_P(node_name, &hd->alias, d) ;
+ }
+ else
+ {
+ uint32_t d ;
+ if (!stralloc_catb(&hd->storage, ".", 2)) goto err ;
+ if (!avltree_search(&hd->byfqdn, hd->storage.s + mark, &d))
+ {
+ if (!gensetdyn_new(&hd->fqdn, &d)) goto err ;
+ GENSETDYN_P(node_name, &hd->fqdn, d)->pos = mark ;
+ GENSETDYN_P(node_name, &hd->fqdn, d)->ipv4 = stralloc_zero ;
+ GENSETDYN_P(node_name, &hd->fqdn, d)->ipv6 = stralloc_zero ;
+ if (!avltree_insert(&hd->byfqdn, d)) goto err ;
+ }
+ else hd->storage.len = mark ;
+ noden = GENSETDYN_P(node_name, &hd->fqdn, d) ;
+ }
+ for (; i < genalloc_len(size_t, &node->names) ; i++)
+ if (!strcmp(hd->storage.s + mark, hd->storage.s + genalloc_s(size_t, &node->names)[i])) break ;
+ if (i >= genalloc_len(size_t, &node->names))
+ if (!genalloc_catb(size_t, &node->names, &mark, 1)) goto err ;
+ if (flags & 1)
+ {
+ for (i = 0 ; i < noden->ipv6.len ; i += 16)
+ if (!memcmp(node->addr, noden->ipv6.s + i, 16)) break ;
+ if (i >= noden->ipv6.len)
+ if (!stralloc_catb(&noden->ipv6, node->addr, 16)) goto err ;
+ }
+ else
+ {
+ for (i = 0 ; i < noden->ipv4.len ; i += 4)
+ if (!memcmp(node->addr, noden->ipv4.s + i, 4)) break ;
+ if (i >= noden->ipv4.len)
+ if (!stralloc_catb(&noden->ipv4, node->addr, 4)) goto err ;
+ }
+ mark = hd->storage.len ;
+ }
+ if (c & 0x40) flags |= 2 ;
+ }
+ if (state > 0x06) return (errno = EILSEQ, 0) ;
+ return 1 ;
+
+ err:
+ hostdata_free(hd) ;
+ return 0 ;
+}
+
+ /* Writing */
+
+static int name_write_iter (void *data, void *aux)
+{
+ node_name *node = data ;
+ hdcm *blah = aux ;
+ struct iovec kv[2] = { { .iov_base = "q4:", .iov_len = 3 }, { .iov_base = blah->hd->storage.s + node->pos, .iov_len = strlen(blah->hd->storage.s + node->pos) + 1 } } ;
+ struct iovec dv = { .iov_base = node->ipv4.s, .iov_len = node->ipv4.len } ;
+ if (node->ipv4.len && !cdbmake_addv(blah->cm, kv, 2, &dv, 1)) return 0 ;
+ if (node->ipv6.len)
+ {
+ ((char *)kv[0].iov_base)[1] = '6' ;
+ dv.iov_base = node->ipv6.s ; dv.iov_len = node->ipv6.len ;
+ if (!cdbmake_addv(blah->cm, kv, 2, &dv, 1)) return 0 ;
+ }
+ return 1 ;
+}
+
+static int ip_write_iter (void *data, void *aux)
+{
+ node_ip *node = data ;
+ size_t n = genalloc_len(size_t, &node->names) ;
+ if (n)
+ {
+ hdcm *blah = aux ;
+ size_t const *p = genalloc_s(size_t, &node->names) ;
+ struct iovec kv[3] = { { .iov_base = blah->key, .iov_len = 2 }, { .iov_base = ":", .iov_len = 1 }, { .iov_base = node->addr, .iov_len = blah->key[1] == '6' ? 16 : 4 } } ;
+ struct iovec dv[n] ;
+ for (size_t i = 0 ; i < n ; i++)
+ {
+ dv[i].iov_base = blah->hd->storage.s + p[i] ;
+ dv[i].iov_len = strlen(blah->hd->storage.s + p[i]) + 1 ;
+ }
+ if (!cdbmake_addv(blah->cm, kv, 3, dv, n)) return 0 ;
+ }
+ return 1 ;
+}
+
+static int s6dns_hosts_write (hostdata *hd, cdbmaker *cm)
+{
+ hdcm blah = { .hd = hd, .cm = cm, .key = { 'q', '4' } } ;
+ if (gensetdyn_iter(&hd->alias, &name_write_iter, &blah) < gensetdyn_n(&hd->alias)) return 0 ;
+ blah.key[0] = 'a' ;
+ if (gensetdyn_iter(&hd->fqdn, &name_write_iter, &blah) < gensetdyn_n(&hd->fqdn)) return 0 ;
+ blah.key[0] = 'p' ;
+ if (gensetdyn_iter(&hd->ipv4, &ip_write_iter, &blah) < gensetdyn_n(&hd->ipv4)) return 0 ;
+ blah.key[1] = '6' ;
+ if (gensetdyn_iter(&hd->ipv6, &ip_write_iter, &blah) < gensetdyn_n(&hd->ipv6)) return 0 ;
+ return 1 ;
+}
+
+
+ /* Capstone */
+
+int s6dns_hosts_compile (int fdr, int fdw)
+{
+ hostdata hd = HOSTDATA_ZERO ;
+ {
+ char buf[BUFFER_INSIZE] ;
+ buffer b = BUFFER_INIT(&buffer_read, fdr, buf, BUFFER_INSIZE) ;
+ avltree_init(&hd.byalias, 3, 3, 8, &byalias_dtok, &name_cmp, &hd) ;
+ avltree_init(&hd.byfqdn, 3, 3, 8, &byfqdn_dtok, &name_cmp, &hd) ;
+ avltree_init(&hd.byipv4, 3, 3, 8, &byipv4_dtok, &ipv4_cmp, &hd) ;
+ avltree_init(&hd.byipv6, 3, 3, 8, &byipv6_dtok, &ipv6_cmp, &hd) ;
+ if (!s6dns_hosts_parse(&b, &hd)) return 0 ;
+ }
+ {
+ cdbmaker cm = CDBMAKER_ZERO ;
+ if (!cdbmake_start(&cm, fdw)) goto err ;
+ if (!s6dns_hosts_write(&hd, &cm)) goto err ;
+ if (!cdbmake_finish(&cm)) goto err ;
+ }
+ hostdata_free(&hd) ;
+ return 1 ;
+
+ err:
+ hostdata_free(&hd) ;
+ return 0 ;
+}
diff --git a/src/libs6dns/s6dns_hosts_compile.txt b/src/libs6dns/s6dns_hosts_compile.txt
new file mode 100644
index 0000000..97c5bac
--- /dev/null
+++ b/src/libs6dns/s6dns_hosts_compile.txt
@@ -0,0 +1,31 @@
+class | 0 1 2 3 4 5 6 7 8 9
+st\ev | \0 space # \n - . : 0-9 alpha other
+
+START | p p p
+00 | END START COMMENT START X X IP IP IP X
+
+COMMENT |
+01 | END COMMENT COMMENT START COMMENT COMMENT COMMENT COMMENT COMMENT COMMENT
+
+IP | s s sa p p p p
+02 | END IPDONE X START X IP IP IP IP X
+
+IPDONE | p
+03 | END IPDONE COMMENT START X X X X NAME X
+
+NAME | f fn f p p p p
+04 | END NAMES X START NAME NAME X NAME NAME X
+
+NAMES | p
+05 | END NAMES COMMENT START X X X X NAME X
+
+END = 06
+X = 07
+
+state: 3 bits
+actions: 4 bits
+
+0x08 p store cur
+0x10 s scan IP, reset fqdn
+0x20 f scan name
+0x40 n fqdn done, now aliases
diff --git a/src/libs6dns/s6dns_hosts_here.c b/src/libs6dns/s6dns_hosts_here.c
new file mode 100644
index 0000000..4be4969
--- /dev/null
+++ b/src/libs6dns/s6dns_hosts_here.c
@@ -0,0 +1,7 @@
+/* ISC license. */
+
+#include <skalibs/cdb.h>
+
+#include <s6-dns/hosts.h>
+
+cdb s6dns_hosts_here = CDB_ZERO ;
diff --git a/src/libs6dns/s6dns_hosts_init.c b/src/libs6dns/s6dns_hosts_init.c
new file mode 100644
index 0000000..d3cd863
--- /dev/null
+++ b/src/libs6dns/s6dns_hosts_init.c
@@ -0,0 +1,62 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include <skalibs/posixplz.h>
+#include <skalibs/cdb.h>
+#include <skalibs/djbunix.h>
+
+#include <s6-dns/hosts.h>
+
+int s6dns_hosts_init (void)
+{
+ int fdr, fdw ;
+ char tmp[24] = "/tmp/hosts.cdb:XXXXXX" ;
+ int fdc = openc_read("/etc/hosts.cdb") ;
+ if (fdc >= 0)
+ {
+ struct stat stc, str ;
+ if (fstat(fdc, &stc) == -1) goto errc ;
+ if (stat("/etc/hosts", &str) == -1)
+ {
+ if (errno == ENOENT) goto useit ;
+ else goto errc ;
+ }
+ if (stc.st_mtim > str.st_mtim) goto useit ;
+ fd_close(fdc) ;
+ }
+ fdr = openc_read("/etc/hosts") ;
+ if (fdr == -1) return errno == ENOENT ? (errno = 0, 0) : -1 ;
+ fdw = mkstemp(tmp) ;
+ if (fdw == -1) goto errr ;
+ if (!s6dns_hosts_compile(fdr, fdw)) goto errw ;
+ if (lseek(fdw, 0, SEEK_SET) == -1) goto errw ;
+ if (!cdb_init_fromfd(&s6dns_hosts_here, fdw)) goto errw ;
+ fd_close(fdw) ;
+ unlink_void(tmp) ;
+ fd_close(fdr) ;
+ return 1 ;
+
+ errw:
+ fd_close(fdw) ;
+ unlink_void(tmp) ;
+ errr:
+ fd_close(fdr) ;
+ return -1 ;
+
+ errc:
+ fd_close(fdc) ;
+ return -1 ;
+
+ useit:
+ if (!cdb_init_fromfd(&s6dns_hosts_here, fdc))
+ {
+ fd_close(fdc) ;
+ return 0 ;
+ }
+ fd_close(fdc) ;
+ return 1 ;
+}