diff options
Diffstat (limited to 'src/libs6dns')
-rw-r--r-- | src/libs6dns/deps-lib/s6dns | 1 | ||||
-rw-r--r-- | src/libs6dns/s6dns_hosts_compile.c | 357 | ||||
-rw-r--r-- | src/libs6dns/s6dns_hosts_compile.txt | 31 | ||||
-rw-r--r-- | src/libs6dns/s6dns_hosts_here.c | 7 | ||||
-rw-r--r-- | src/libs6dns/s6dns_hosts_init.c | 62 |
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 ; +} |