summaryrefslogtreecommitdiff
path: root/src/skadns
diff options
context:
space:
mode:
Diffstat (limited to 'src/skadns')
-rwxr-xr-xsrc/skadns/deps-exe/skadnsd4
-rw-r--r--src/skadns/deps-lib/skadns10
-rw-r--r--src/skadns/skadns_cancel.c23
-rw-r--r--src/skadns/skadns_end.c24
-rw-r--r--src/skadns/skadns_packet.c16
-rw-r--r--src/skadns/skadns_packetlen.c16
-rw-r--r--src/skadns/skadns_release.c26
-rw-r--r--src/skadns/skadns_send.c41
-rw-r--r--src/skadns/skadns_start.c10
-rw-r--r--src/skadns/skadns_startf.c12
-rw-r--r--src/skadns/skadns_update.c45
-rw-r--r--src/skadns/skadns_zero.c5
-rw-r--r--src/skadns/skadnsd.c199
13 files changed, 431 insertions, 0 deletions
diff --git a/src/skadns/deps-exe/skadnsd b/src/skadns/deps-exe/skadnsd
new file mode 100755
index 0000000..4181fd6
--- /dev/null
+++ b/src/skadns/deps-exe/skadnsd
@@ -0,0 +1,4 @@
+-ls6dns
+-lskarnet
+${SOCKET_LIB}
+${TAINNOW_LIB}
diff --git a/src/skadns/deps-lib/skadns b/src/skadns/deps-lib/skadns
new file mode 100644
index 0000000..570a6f5
--- /dev/null
+++ b/src/skadns/deps-lib/skadns
@@ -0,0 +1,10 @@
+skadns_cancel.o
+skadns_end.o
+skadns_packet.o
+skadns_packetlen.o
+skadns_release.o
+skadns_send.o
+skadns_start.o
+skadns_startf.o
+skadns_update.o
+skadns_zero.o
diff --git a/src/skadns/skadns_cancel.c b/src/skadns/skadns_cancel.c
new file mode 100644
index 0000000..13db918
--- /dev/null
+++ b/src/skadns/skadns_cancel.c
@@ -0,0 +1,23 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/error.h>
+#include <skalibs/tai.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/skaclient.h>
+#include <s6-dns/skadns.h>
+
+int skadns_cancel (skadns_t *a, uint16 id, tain_t const *deadline, tain_t *stamp)
+{
+ char pack[3] = "--q" ;
+ char err ;
+ register skadnsanswer_t *p = GENSETDYN_P(skadnsanswer_t, &a->q, id) ;
+ if (!error_isagain(p->status)) return skadns_release(a, id) ;
+ uint16_pack_big(pack, id) ;
+ if (!skaclient_send(&a->connection, pack, 3, &skaclient_default_cb, &err, deadline, stamp)) return 0 ;
+ if (!err) return gensetdyn_delete(&a->q, id) ;
+ if (err != ENOENT) return (errno = err, 0) ;
+ p->status = ECANCELED ;
+ return 1 ;
+}
diff --git a/src/skadns/skadns_end.c b/src/skadns/skadns_end.c
new file mode 100644
index 0000000..6f5f01b
--- /dev/null
+++ b/src/skadns/skadns_end.c
@@ -0,0 +1,24 @@
+/* ISC license. */
+
+#include <skalibs/alloc.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/skaclient.h>
+#include <s6-dns/skadns.h>
+
+static int skadnsanswer_free (char *p, void *stuff)
+{
+ register skadnsanswer_t *q = (skadnsanswer_t_ref)p ;
+ alloc_free(&q->data) ;
+ (void)stuff ;
+ return 1 ;
+}
+
+void skadns_end (skadns_t *a)
+{
+ skaclient_end(&a->connection) ;
+ genalloc_free(uint16, &a->list) ;
+ gensetdyn_iter(&a->q, &skadnsanswer_free, 0) ;
+ gensetdyn_free(&a->q) ;
+ *a = skadns_zero ;
+}
diff --git a/src/skadns/skadns_packet.c b/src/skadns/skadns_packet.c
new file mode 100644
index 0000000..c34b3a1
--- /dev/null
+++ b/src/skadns/skadns_packet.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/gensetdyn.h>
+#include <s6-dns/skadns.h>
+
+char const *skadns_packet (skadns_t const *a, uint16 id)
+{
+ register skadnsanswer_t *p = GENSETDYN_P(skadnsanswer_t, &a->q, id) ;
+ switch (p->status)
+ {
+ case 0 : return (char const *)p->data ;
+ default : return (errno = p->status, (char const *)0) ;
+ }
+}
diff --git a/src/skadns/skadns_packetlen.c b/src/skadns/skadns_packetlen.c
new file mode 100644
index 0000000..34cbb28
--- /dev/null
+++ b/src/skadns/skadns_packetlen.c
@@ -0,0 +1,16 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/gensetdyn.h>
+#include <s6-dns/skadns.h>
+
+int skadns_packetlen (skadns_t const *a, uint16 id)
+{
+ register skadnsanswer_t *p = GENSETDYN_P(skadnsanswer_t, &a->q, id) ;
+ switch (p->status)
+ {
+ case 0 : return p->len ;
+ default : return (errno = p->status, -1) ;
+ }
+}
diff --git a/src/skadns/skadns_release.c b/src/skadns/skadns_release.c
new file mode 100644
index 0000000..9fba737
--- /dev/null
+++ b/src/skadns/skadns_release.c
@@ -0,0 +1,26 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/alloc.h>
+#include <skalibs/gensetdyn.h>
+#include <s6-dns/skadns.h>
+
+int skadns_release (skadns_t *a, uint16 id)
+{
+ register skadnsanswer_t *p = GENSETDYN_P(skadnsanswer_t, &a->q, id) ;
+ switch (p->status)
+ {
+ case 0 :
+ alloc_free(p->data) ; p->data = 0 ; p->len = 0 ;
+ break ;
+ case EAGAIN :
+ case ECANCELED :
+ return (errno = EBUSY, 0) ;
+ case EINVAL :
+ return (errno = EINVAL, 0) ;
+ default : break ;
+ }
+ p->status = EINVAL ;
+ return gensetdyn_delete(&a->q, id) ;
+}
diff --git a/src/skadns/skadns_send.c b/src/skadns/skadns_send.c
new file mode 100644
index 0000000..7ee04c7
--- /dev/null
+++ b/src/skadns/skadns_send.c
@@ -0,0 +1,41 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/uint16.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/siovec.h>
+#include <skalibs/tai.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/skaclient.h>
+#include <s6-dns/s6dns-domain.h>
+#include <s6-dns/skadns.h>
+
+static skadnsanswer_t const skadnsanswer_initial = { .status = EAGAIN, .data = 0, .len = 0 } ;
+
+int skadns_send (skadns_t *a, uint16 *u, s6dns_domain_t const *d, uint16 qtype, tain_t const *limit, tain_t const *deadline, tain_t *stamp)
+{
+ unsigned int i ;
+ char tmp[17] = "--Q" ;
+ char err ;
+ siovec_t v[2] = { { .s = tmp, .len = 17 }, { .s = d->s, .len = d->len } } ;
+ if (!gensetdyn_new(&a->q, &i)) return 0 ;
+ uint16_pack_big(tmp, (uint16)i) ;
+ uint16_pack_big(tmp + 3, qtype) ;
+ if (limit) tain_pack(tmp + 5, limit) ; else byte_zero(tmp + 5, 12) ;
+ if (!skaclient_sendv(&a->connection, v, 2, &skaclient_default_cb, &err, deadline, stamp))
+ {
+ register int e = errno ;
+ gensetdyn_delete(&a->q, i) ;
+ errno = e ;
+ return 0 ;
+ }
+ if (err)
+ {
+ gensetdyn_delete(&a->q, i) ;
+ return (errno = err, 0) ;
+ }
+ *GENSETDYN_P(skadnsanswer_t, &a->q, i) = skadnsanswer_initial ;
+ *u = i ;
+ return 1 ;
+}
diff --git a/src/skadns/skadns_start.c b/src/skadns/skadns_start.c
new file mode 100644
index 0000000..3dccb54
--- /dev/null
+++ b/src/skadns/skadns_start.c
@@ -0,0 +1,10 @@
+/* ISC license. */
+
+#include <skalibs/tai.h>
+#include <skalibs/skaclient.h>
+#include <s6-dns/skadns.h>
+
+int skadns_start (skadns_t *a, char const *path, tain_t const *deadline, tain_t *stamp)
+{
+ return skaclient_start_b(&a->connection, &a->buffers, path, SKADNS_BANNER1, SKADNS_BANNER1_LEN, SKADNS_BANNER2, SKADNS_BANNER2_LEN, deadline, stamp) ;
+}
diff --git a/src/skadns/skadns_startf.c b/src/skadns/skadns_startf.c
new file mode 100644
index 0000000..ac19a0c
--- /dev/null
+++ b/src/skadns/skadns_startf.c
@@ -0,0 +1,12 @@
+/* ISC license. */
+
+#include <skalibs/environ.h>
+#include <skalibs/tai.h>
+#include <skalibs/skaclient.h>
+#include <s6-dns/skadns.h>
+
+int skadns_startf (skadns_t *a, tain_t const *deadline, tain_t *stamp)
+{
+ static char const *const cargv[2] = { SKADNSD_PROG, 0 } ;
+ return skaclient_startf_b(&a->connection, &a->buffers, cargv[0], cargv, (char const *const *)environ, SKACLIENT_OPTION_WAITPID, SKADNS_BANNER1, SKADNS_BANNER1_LEN, SKADNS_BANNER2, SKADNS_BANNER2_LEN, deadline, stamp) ;
+}
diff --git a/src/skadns/skadns_update.c b/src/skadns/skadns_update.c
new file mode 100644
index 0000000..50f3611
--- /dev/null
+++ b/src/skadns/skadns_update.c
@@ -0,0 +1,45 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <skalibs/error.h>
+#include <skalibs/uint16.h>
+#include <skalibs/alloc.h>
+#include <skalibs/bytestr.h>
+#include <skalibs/genalloc.h>
+#include <skalibs/gensetdyn.h>
+#include <skalibs/unixmessage.h>
+#include <skalibs/skaclient.h>
+#include <s6/skadns.h>
+
+static int msghandler (unixmessage_t const *m, void *context)
+{
+ skadns_t *a = (skadns_t *)context ;
+ skadnsanswer_t *p ;
+ uint16 id ;
+ if (m->len < 3 || m->nfds) return (errno = EPROTO, 0) ;
+ uint16_unpack_big(m->s, &id) ;
+ p = GENSETDYN_P(skadnsanswer_t, &a->q, id) ;
+ if (p->status == ECANCELED)
+ {
+ p->status = EINVAL ;
+ return gensetdyn_delete(&a->q, id) ;
+ }
+ if (!error_isagain(p->status)) return (errno = EINVAL, 0) ;
+ if (!genalloc_readyplus(uint16, &a->list, 1)) return 0 ;
+ if (!m->s[2])
+ {
+ p->data = alloc(m->len-3) ;
+ if (!p->data) return 0 ;
+ byte_copy(p->data, m->len-3, m->s+3) ;
+ p->len = m->len-3 ;
+ }
+ p->status = m->s[2] ;
+ genalloc_append(uint16, &a->list, &id) ;
+ return 1 ;
+}
+
+int skadns_update (skadns_t *a)
+{
+ genalloc_setlen(uint16, &a->list, 0) ;
+ return skaclient_update(&a->connection, &msghandler, a) ;
+}
diff --git a/src/skadns/skadns_zero.c b/src/skadns/skadns_zero.c
new file mode 100644
index 0000000..1842d2e
--- /dev/null
+++ b/src/skadns/skadns_zero.c
@@ -0,0 +1,5 @@
+/* ISC license. */
+
+#include <s6-dns/skadns.h>
+
+skadns_t const skadns_zero = SKADNS_ZERO ;
diff --git a/src/skadns/skadnsd.c b/src/skadns/skadnsd.c
new file mode 100644
index 0000000..7b5419f
--- /dev/null
+++ b/src/skadns/skadnsd.c
@@ -0,0 +1,199 @@
+/* ISC license. */
+
+#include <errno.h>
+#include <signal.h>
+#include <skalibs/uint16.h>
+#include <skalibs/error.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/sig.h>
+#include <skalibs/tai.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/iopause.h>
+#include <skalibs/unixmessage.h>
+#include <skalibs/skaclient.h>
+#include <s6-dns/s6dns.h>
+#include <s6-dns/skadns.h>
+
+typedef struct dnsio_s dnsio_t, *dnsio_t_ref ;
+struct dnsio_s
+{
+ unsigned int xindex ;
+ s6dns_engine_t dt ;
+ uint16 id ;
+} ;
+#define DNSIO_ZERO { .xindex = SKADNS_MAXCONCURRENCY, .dt = S6DNS_ENGINE_ZERO, .id = 0 }
+
+static dnsio_t a[SKADNS_MAXCONCURRENCY] ;
+static unsigned int sp = 0 ;
+
+static void remove (unsigned int i)
+{
+ dnsio_t tmp ;
+ tmp = a[sp-1] ;
+ a[--sp] = a[i] ;
+ a[i] = tmp ;
+}
+
+static void fail (unsigned int i)
+{
+ char pack[3] ;
+ unixmessage_t m = { .s = pack, len = 3, .fds = 0, .nfds = 0 } ;
+ uint16_pack_big(pack, a[i].id) ;
+ pack[2] = a[i].dt.status ;
+ s6dns_engine_recycle(&a[i].dt) ;
+ remove(i) ;
+ if (!unixmessage_put(unixmessage_sender_x, &m))
+ strerr_diefu1sys(111, "unixmessage_put") ;
+}
+
+static void answer (char c)
+{
+ unixmessage_t m = { .s = &c, .len = 1, .fds = 0, .nfds = 0 } ;
+ if (!unixmessage_put(unixmessage_sender_1, &m))
+ strerr_diefu1sys(111, "unixmessage_put") ;
+}
+
+static int parse_protocol (unixmessage_t const *m, void *context)
+{
+ uint16 id ;
+ if (m->len < 3 || m->nfds) strerr_dief1x(100, "invalid client request") ;
+ uint16_unpack_big(m->s, &id) ;
+ switch (m->s[2]) /* protocol parsing */
+ {
+ case 'Q' : /* send a query */
+ {
+ tain_t limit ;
+ uint16 qtype ;
+ if (m->len < 21) strerr_dief1x(100, "invalid client request") ;
+ if (sp >= SKADNS_MAXCONCURRENCY)
+ {
+ answer(ENFILE) ;
+ break ;
+ }
+ uint16_unpack_big(m->s + 3, &qtype) ;
+ if (byte_diff(m->s + 5, 12, "\0\0\0\0\0\0\0\0\0\0\0"))
+ tain_unpack(m->s + 5, &limit) ;
+ else tain_add_g(&limit, &tain_infinite_relative) ;
+ if (!s6dns_engine_init_g(&a[sp].dt, &s6dns_rci_here.servers, 1, m->s + 17, m->len - 17, qtype, &limit))
+ {
+ answer(errno) ;
+ break ;
+ }
+ a[sp++].id = id ;
+ answer(0) ;
+ break ;
+ }
+ case 'q' : /* cancel a query */
+ {
+ register unsigned int i = 0 ;
+ for (; i < sp ; i++) if (a[i].id == id) break ;
+ if (i >= sp)
+ {
+ answer(ENOENT) ;
+ break ;
+ }
+ s6dns_engine_recycle(&a[i].dt) ;
+ remove(i) ;
+ answer(0) ;
+ break ;
+ }
+ default : strerr_dief1x(100, "invalid client request") ;
+ }
+ (void)context ;
+ return 1 ;
+}
+
+int main (void)
+{
+ PROG = "skadnsd" ;
+
+ if (ndelay_on(0) < 0) strerr_diefu2sys(111, "ndelay_on ", "0") ;
+ if (ndelay_on(1) < 0) strerr_diefu2sys(111, "ndelay_on ", "1") ;
+ if (sig_ignore(SIGPIPE) < 0) strerr_diefu1sys(111, "ignore SIGPIPE") ;
+ tain_now_g() ;
+ if (!s6dns_init()) strerr_diefu1sys(111, "s6dns_init") ;
+
+ {
+ tain_t deadline ;
+ tain_addsec_g(&deadline, 2) ;
+ if (!skaclient_server_01x_init_g(SKADNS_BANNER1, SKADNS_BANNER1_LEN, SKADNS_BANNER2, SKADNS_BANNER2_LEN, &deadline))
+ strerr_diefu1sys(111, "sync with client") ;
+ }
+ {
+ static dnsio_t const zero = DNSIO_ZERO ;
+ register unsigned int i = 0 ;
+ for (; i < SKADNS_MAXCONCURRENCY ; i++) a[i] = zero ;
+ }
+
+ for (;;)
+ {
+ iopause_fd x[3 + sp] ;
+ register int r ;
+
+ x[0].fd = 0 ; x[0].events = IOPAUSE_EXCEPT | IOPAUSE_READ ;
+ x[1].fd = 1 ; x[1].events = IOPAUSE_EXCEPT | (unixmessage_sender_isempty(unixmessage_sender_1) ? 0 : IOPAUSE_WRITE) ;
+ x[2].fd = unixmessage_sender_fd(unixmessage_sender_x) ;
+ x[2].events = IOPAUSE_EXCEPT | (unixmessage_sender_isempty(unixmessage_sender_x) ? 0 : IOPAUSE_WRITE) ;
+ {
+ tain_t deadline = TAIN_INFINITE ;
+ register unsigned int i = 0 ;
+ for (; i < sp ; i++)
+ {
+ register unsigned int j = 3 + i ;
+ s6dns_engine_nextdeadline(&a[i].dt, &deadline) ;
+ x[j].fd = a[i].dt.fd ;
+ x[j].events = 0 ;
+ if (s6dns_engine_isreadable(&a[i].dt)) x[j].events |= IOPAUSE_READ ;
+ if (s6dns_engine_iswritable(&a[i].dt)) x[j].events |= IOPAUSE_WRITE ;
+ a[i].xindex = j ;
+ }
+ r = iopause_g(x, 3 + sp, &deadline) ;
+ }
+ if (r < 0) strerr_diefu1sys(111, "iopause") ;
+ if (!r)
+ {
+ register unsigned int i = 0 ;
+ for (; i < sp ; i++)
+ if (s6dns_engine_timeout_g(&a[i].dt)) fail(i--) ;
+ continue ;
+ }
+
+ if (x[1].revents & IOPAUSE_WRITE)
+ if ((unixmessage_sender_flush(unixmessage_sender_1) < 0) && !error_isagain(errno))
+ strerr_diefu1sys(111, "flush stdout") ;
+ if (x[2].revents & IOPAUSE_WRITE)
+ if ((unixmessage_sender_flush(unixmessage_sender_x) < 0) && !error_isagain(errno))
+ strerr_diefu1sys(111, "flush asyncout") ;
+
+ {
+ register unsigned int i = 0 ;
+ for (; i < sp ; i++) if (x[a[i].xindex].revents)
+ {
+ register int r = s6dns_engine_event_g(&a[i].dt) ;
+ if (r < 0) fail(i--) ;
+ else if (r)
+ {
+ char pack[3] ;
+ siovec_t v[2] = { { .s = pack, .len = 3 }, { .s = s6dns_engine_packet(&a[i].dt), .len = s6dns_engine_packetlen(&a[i].dt) } } ;
+ unixmessage_v_t mv = { .v = v, .vlen = 2, .fds = 0, .nfds = 0 } ;
+ uint16_pack_big(pack, a[i].id) ;
+ pack[2] = 0 ;
+ if (!unixmessage_putv(unixmessage_sender_x, v, 2))
+ strerr_diefu1sys(111, "unixmessage_put") ;
+ s6dns_engine_recycle(&a[i].dt) ;
+ remove(i--) ;
+ }
+ }
+ }
+
+ if (!unixmessage_receiver_isempty(unixmessage_receiver_0) || x[0].revents & IOPAUSE_READ)
+ {
+ if (unixmessage_handle(unixmessage_receiver_0, &parse_protocol, 0) < 0)
+ {
+ if (errno == EPIPE) break ; /* normal exit */
+ strerr_diefu1sys(111, "handle messages from client") ;
+ }
+ }
+ }
+ return 0 ;
+}