diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2014-12-10 03:05:47 +0000 |
---|---|---|
committer | Laurent Bercot <ska-skaware@skarnet.org> | 2014-12-10 03:05:47 +0000 |
commit | 416ef5e2bf59bb2e45066a1d5d91ac677c0f48e5 (patch) | |
tree | 1c746d673dcec7a8488c6ac51db8245411034376 /src/skadns | |
download | s6-dns-416ef5e2bf59bb2e45066a1d5d91ac677c0f48e5.tar.xz |
Initial commit
Diffstat (limited to 'src/skadns')
-rwxr-xr-x | src/skadns/deps-exe/skadnsd | 4 | ||||
-rw-r--r-- | src/skadns/deps-lib/skadns | 10 | ||||
-rw-r--r-- | src/skadns/skadns_cancel.c | 23 | ||||
-rw-r--r-- | src/skadns/skadns_end.c | 24 | ||||
-rw-r--r-- | src/skadns/skadns_packet.c | 16 | ||||
-rw-r--r-- | src/skadns/skadns_packetlen.c | 16 | ||||
-rw-r--r-- | src/skadns/skadns_release.c | 26 | ||||
-rw-r--r-- | src/skadns/skadns_send.c | 41 | ||||
-rw-r--r-- | src/skadns/skadns_start.c | 10 | ||||
-rw-r--r-- | src/skadns/skadns_startf.c | 12 | ||||
-rw-r--r-- | src/skadns/skadns_update.c | 45 | ||||
-rw-r--r-- | src/skadns/skadns_zero.c | 5 | ||||
-rw-r--r-- | src/skadns/skadnsd.c | 199 |
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 ; +} |