From f7f7332afafd4f965c5ef1d45cc1c7da9275c6ef Mon Sep 17 00:00:00 2001 From: David Timber Date: Mon, 14 Sep 2020 15:47:30 +0930 Subject: * Add "--enable-static" configure option * Change "PRNE_DEBUG" macro use * Add "PRNE_VERBOSE" * Impl "recon" * Add "inet.h" for Internet Protocol stuff * Changes regarding "PRNE_RND_WELL512_SEEDLEN" * Add prne_own_realloc() for objects with multiple array memebers * Add prne_add_timespec() --- src/Makefile.am | 40 +- src/data/recon.sample.conf | 10 + src/htbt.c | 2 +- src/inet.c | 156 ++++++++ src/inet.h | 22 ++ src/proone-recon.c | 291 ++++++++++++++ src/proone-rnd.c | 4 +- src/proone.c | 9 +- src/recon.c | 916 +++++++++++++++++++++++++++++++++++++++++++++ src/recon.h | 48 +++ src/resolv.c | 24 +- src/rnd.h | 4 +- src/rnd_well512.c | 8 +- src/util_ct.h | 10 +- src/util_rt.c | 71 ++++ src/util_rt.h | 23 ++ 16 files changed, 1592 insertions(+), 46 deletions(-) create mode 100644 src/data/recon.sample.conf create mode 100644 src/inet.c create mode 100644 src/inet.h create mode 100644 src/proone-recon.c create mode 100644 src/recon.c create mode 100644 src/recon.h (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am index ce079d4..f2e68d6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,11 +1,30 @@ BIN_ALIGNMENT = 8 -AM_CFLAGS = -std=c11 -pedantic -Wall -Wextra -Wno-switch -D_POSIX_C_SOURCE=200112L -Wno-unused-parameter -DPRNE_BIN_ALIGNMENT=$(BIN_ALIGNMENT) -fdata-sections -ffunction-sections -Wl,--gc-sections +AM_CFLAGS =\ + -std=c11\ + -pedantic\ + -Wall\ + -Wextra\ + -Wno-switch\ + -D_POSIX_C_SOURCE=200112L\ + -Wno-unused-parameter\ + -DPRNE_BIN_ALIGNMENT=$(BIN_ALIGNMENT)\ + -fdata-sections\ + -ffunction-sections\ + -Wl,--gc-sections\ + -DPRNE_VERBOSE=$(PRNE_VERBOSE) + +AM_LDFLAGS = + if DEBUG -AM_CFLAGS += -g -O0 -DPRNE_DEBUG +AM_CFLAGS += -g -O0 -DPRNE_DEBUG=1 else -AM_CFLAGS += -g -Os +AM_CFLAGS += -g -Os -DPRNE_DEBUG=0 +endif +if STATIC_RT +AM_LDFLAGS += -static endif + # Override AM's default to remove "-I." flag DEFAULT_INCLUDES = @@ -22,7 +41,8 @@ bin_PROGRAMS =\ proone-stress\ proone-ipaddr-arr\ proone-htbthost\ - proone-rnd + proone-rnd\ + proone-recon proone_tests =\ proone-test_proto\ @@ -44,7 +64,9 @@ libproone_a_SOURCES =\ htbt.c\ iobuf.c\ rnd.c\ - rnd_well512.c + rnd_well512.c\ + recon.c\ + inet.c proone: proone.bin dvault.bin cp -fa proone.bin proone @@ -54,8 +76,6 @@ proone: proone.bin dvault.bin ./build-utils.sh append-uint32 0 proone cat dvault.bin >> proone -proone_bin_CFLAGS = $(AM_CFLAGS) -fwhole-program -proone_bin_LDFLAGS = -static proone_bin_LDADD = libproone.a proone_bin_SOURCES =\ proone.c @@ -81,18 +101,18 @@ proone_htbthost_SOURCES = proone-htbthost.c proone_ipaddr_arr_SOURCES = proone-ipaddr-arr.c proone_stress_LDADD = libproone.a -proone_stress_LDFLAGS = -static proone_stress_SOURCES = proone-stress.c proone_rnd_LDADD = libproone.a proone_rnd_SOURCES = proone-rnd.c +proone_recon_LDADD = libproone.a +proone_recon_SOURCES = proone-recon.c + proone_test_proto_LDADD = libproone.a -proone_test_proto_LDFLAGS = proone_test_proto_SOURCES = proone-test_proto.c proone_test_util_LDADD = libproone.a -proone_test_util_LDFLAGS = proone_test_util_SOURCES = proone-test_util.c testlist: $(proone_tests) diff --git a/src/data/recon.sample.conf b/src/data/recon.sample.conf new file mode 100644 index 0000000..96c3d00 --- /dev/null +++ b/src/data/recon.sample.conf @@ -0,0 +1,10 @@ +# IPv4 target networks +T 192.18.0.0/24 # Test pool A +T 192.18.1.0/25# Test pool B + # IPv6 target networks +T fc00:A::/96 # Test pool C + T fc00:B::/98 # Test pool D + +# Blacklists +BL 192.168.0.1/24 # My Private Net (IPv4) +BL fd00:ABBA::/64 # My Private Net (IPv6) diff --git a/src/htbt.c b/src/htbt.c index 0a1b3f7..90077de 100644 --- a/src/htbt.c +++ b/src/htbt.c @@ -576,7 +576,7 @@ static void htbt_do_cmd ( setsid(); close(STDIN_FILENO); // Inherit these if DEBUG -#if !defined(PRNE_DEBUG) +#if !PRNE_DEBUG close(STDOUT_FILENO); close(STDERR_FILENO); #endif diff --git a/src/inet.c b/src/inet.c new file mode 100644 index 0000000..5f7fb7d --- /dev/null +++ b/src/inet.c @@ -0,0 +1,156 @@ +#include "inet.h" +#include "endian.h" + + +void prne_netmask_from_cidr (uint8_t *out, size_t cidr) { + size_t shft = 7; + + while (cidr >= 8) { + *out = 0xFF; + cidr -= 8; + out += 1; + } + *out = 0; + while (cidr > 0) { + *out |= (uint8_t)(1 << shft); + shft -= 1; + cidr -= 1; + } +} + +uint16_t prne_calc_tcp_chksum4 ( + const struct iphdr *ih, + const uint8_t *th, + size_t th_len, + const uint8_t *data, + size_t data_len) +{ + uint_fast32_t sum = 0; + + // pseudo + sum += prne_recmb_msb16( + ((uint8_t*)&ih->saddr)[0], + ((uint8_t*)&ih->saddr)[1]); + sum += prne_recmb_msb16( + ((uint8_t*)&ih->saddr)[2], + ((uint8_t*)&ih->saddr)[3]); + + sum += prne_recmb_msb16( + ((uint8_t*)&ih->daddr)[0], + ((uint8_t*)&ih->daddr)[1]); + sum += prne_recmb_msb16( + ((uint8_t*)&ih->daddr)[2], + ((uint8_t*)&ih->daddr)[3]); + sum += 6; // IPPROTO_TCP + sum += (uint16_t)(th_len + data_len); + + // tcp header + while (th_len > 1) { + sum += prne_recmb_msb16(th[0], th[1]); + th += 2; + th_len -= 2; + } + if (th_len > 0) { + sum += th[0]; + } + + // data + while (data_len > 1) { + sum += prne_recmb_msb16(data[0], data[1]); + data += 2; + data_len -= 2; + } + if (data_len > 0) { + sum += data[0]; + } + + return ~((sum & 0xFFFF) + (sum >> 16)); +} + +uint16_t prne_calc_tcp_chksum6 ( + const struct ipv6hdr *ih, + const uint8_t *th, + size_t th_len, + const uint8_t *data, + size_t data_len) +{ + uint_fast32_t sum = 0; + const uint_fast32_t tcp_length = (uint32_t)(th_len + data_len); + + // pseudo + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->saddr)[0], + ((const uint8_t*)&ih->saddr)[1]); + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->saddr)[2], + ((const uint8_t*)&ih->saddr)[3]); + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->saddr)[4], + ((const uint8_t*)&ih->saddr)[5]); + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->saddr)[6], + ((const uint8_t*)&ih->saddr)[7]); + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->saddr)[8], + ((const uint8_t*)&ih->saddr)[9]); + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->saddr)[10], + ((const uint8_t*)&ih->saddr)[11]); + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->saddr)[12], + ((const uint8_t*)&ih->saddr)[13]); + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->saddr)[14], + ((const uint8_t*)&ih->saddr)[15]); + + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->daddr)[0], + ((const uint8_t*)&ih->daddr)[1]); + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->daddr)[2], + ((const uint8_t*)&ih->daddr)[3]); + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->daddr)[4], + ((const uint8_t*)&ih->daddr)[5]); + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->daddr)[6], + ((const uint8_t*)&ih->daddr)[7]); + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->daddr)[8], + ((const uint8_t*)&ih->daddr)[9]); + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->daddr)[10], + ((const uint8_t*)&ih->daddr)[11]); + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->daddr)[12], + ((const uint8_t*)&ih->daddr)[13]); + sum += prne_recmb_msb16( + ((const uint8_t*)&ih->daddr)[14], + ((const uint8_t*)&ih->daddr)[15]); + + sum += (uint16_t)((tcp_length & 0xFFFF0000) >> 16); + sum += (uint16_t)(tcp_length & 0xFFFF); + sum += 6; // IPPROTO_TCP + + // tcp header + while (th_len > 1) { + sum += prne_recmb_msb16(th[0], th[1]); + th += 2; + th_len -= 2; + } + if (th_len > 0) { + sum += th[0]; + } + + // data + while (data_len > 1) { + sum += prne_recmb_msb16(data[0], data[1]); + data += 2; + data_len -= 2; + } + if (data_len > 0) { + sum += data[0]; + } + + return ~((sum & 0xFFFF) + (sum >> 16)); +} diff --git a/src/inet.h b/src/inet.h new file mode 100644 index 0000000..8e593f5 --- /dev/null +++ b/src/inet.h @@ -0,0 +1,22 @@ +#include +#include +#include + +// TODO: don't use these +#include +#include + + +void prne_netmask_from_cidr (uint8_t *out, size_t cidr); +uint16_t prne_calc_tcp_chksum4 ( + const struct iphdr *ih, + const uint8_t *th, + size_t th_len, + const uint8_t *data, + size_t data_len); +uint16_t prne_calc_tcp_chksum6 ( + const struct ipv6hdr *ih, + const uint8_t *th, + size_t th_len, + const uint8_t *data, + size_t data_len); diff --git a/src/proone-recon.c b/src/proone-recon.c new file mode 100644 index 0000000..d8aa7aa --- /dev/null +++ b/src/proone-recon.c @@ -0,0 +1,291 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include "recon.h" +#include "util_ct.h" +#include "util_rt.h" +#include "inet.h" + + +static regex_t re_entry, re_comment, re_empty; + +static void print_help (FILE *o, const char *prog) { + fprintf( + stderr, + "Usage: %s [port 2] ... [port n]\n" + "Options:\n" + "\t: Path to config file. Pass \"-\" to read stdin\n" + "Config Format: \n" + "\t: \"T\" for target or \"BL\" for blacklist\n" + "\t: /\n" + "\tNote:\n" + "\t\t- Parsed case-insensitively\n" + "\t\t- Lines start with \"#\" are ignored\n" + "Config Example:\n" + "\t# Test pool A\n" + "\tT\t192.18.0.0/24\n" + "\t# Test pool B\n" + "\tT\t192.18.1.0/24\n" + "\t# Test pool C\n" + "\tT\tfc00:A::/96\n" + "\t# Test pool D\n" + "\tT\tfc00:B::/96\n" + "\t# My Private Net (IPv4)\n" + "\tBL\t192.168.0.1/24\n" + "\t# My Private Net (IPv6)\n" + "\tBL\tfd00:ABBA::/64\n", + prog); +} + +static int do_parse_conf (FILE *file, prne_recon_param_t *param) { + static const size_t RM_SIZE = 8; + regmatch_t rm[RM_SIZE]; + char line[2][1024]; + size_t nr_line = 0; + char *ent_spec, *ent_addr, *ent_cidr; + uint8_t cidr; + prne_recon_network_t net; + + while (true) { + if (fgets(line[0], sizeof(line[0]), file) == NULL) { + break; + } + nr_line += 1; + + if (regexec(&re_empty, line[0], RM_SIZE, rm, 0) == 0 || + regexec(&re_comment, line[0], RM_SIZE, rm, 0) == 0) + { + continue; + } + if (regexec(&re_entry, line[0], RM_SIZE, rm, 0) != 0) { + goto INV_LINE; + } + + strcpy(line[1], line[0]); + prne_memzero(&net, sizeof(prne_recon_network_t)); + + line[1][rm[2].rm_eo] = 0; // terminate ENTRY SPEC + line[1][rm[4].rm_eo] = 0; // terminate address + line[1][rm[5].rm_eo] = 0; // terminate CIDR + ent_spec = line[1] + rm[2].rm_so; + ent_addr = line[1] + rm[4].rm_so; + ent_cidr = line[1] + rm[5].rm_so; + prne_transstr(ent_spec, toupper); + prne_transstr(ent_addr, tolower); + + if (inet_pton(AF_INET6, ent_addr, net.addr.addr)) { + net.addr.ver = PRNE_IPV_6; + } + else if (inet_pton(AF_INET, ent_addr, net.addr.addr)) { + net.addr.ver = PRNE_IPV_4; + } + else { + goto INV_LINE; + } + + if (sscanf(ent_cidr, "%"SCNu8, &cidr) != 1 || + (net.addr.ver == PRNE_IPV_6 && cidr > 128) || + (net.addr.ver == PRNE_IPV_4 && cidr > 32)) + { + goto INV_LINE; + } + prne_netmask_from_cidr(net.mask, cidr); + + if (strcmp(ent_spec, "T") == 0) { + prne_assert(prne_alloc_recon_param( + param, + param->blist.cnt, + param->target.cnt + 1, + param->ports.cnt)); + param->target.arr[param->target.cnt - 1] = net; + } + else if (strcmp(ent_spec, "BL") == 0) { + prne_assert(prne_alloc_recon_param( + param, + param->blist.cnt + 1, + param->target.cnt, + param->ports.cnt)); + param->blist.arr[param->blist.cnt - 1] = net; + } + else { + abort(); + } + } + + return 0; +INV_LINE: + fprintf( + stderr, + "*** Invalid entry at line %zu: %s\n", + nr_line, + line[0]); + return 2; +} + +static void evt_cb (const prne_net_endpoint_t *ep) { + char addr_str[prne_op_max(INET_ADDRSTRLEN, INET6_ADDRSTRLEN)]; + const char *fmt; + + switch (ep->addr.ver) { + case PRNE_IPV_4: + inet_ntop(AF_INET, ep->addr.addr, addr_str, sizeof(addr_str)); + fmt = "%s:%"PRIu16"\n"; + break; + case PRNE_IPV_6: + inet_ntop(AF_INET6, ep->addr.addr, addr_str, sizeof(addr_str)); + fmt = "[%s]:%"PRIu16"\n"; + break; + default: abort(); + } + + printf(fmt, addr_str, ep->port); +} + +int main (const int argc, const char **args) { + int ret = 0; + prne_recon_param_t param; + FILE *conf_f; + bool own_conf_f = false; + prne_worker_t wkr; + prne_recon_t *recon; + mbedtls_entropy_context entropy; + mbedtls_ctr_drbg_context ctr_drbg; + sigset_t ss_term; + int caught_sig; + + prne_assert(regcomp( + &re_entry, + // ^(\s+)?(T|BL)(\s+)?([0-9a-f:.]+)\/([0-9]{1,3})(\s+)?(#.*)?$ + // number of captures: 7 + // significant groups: 2, 4, 5 + "^(\\s+)?(T|BL)(\\s+)?([0-9a-f:.]+)\\/([0-9]{1,3})(\\s+)?(#.*)?$", + REG_EXTENDED | REG_ICASE) == 0); + prne_assert(regcomp( + &re_comment, + // ^(\s+)?#.*$ + "^(\\s+)?#.*$", + REG_EXTENDED | REG_ICASE) == 0); + prne_assert(regcomp( + &re_empty, + // ^(\s+)?$ + "^(\\s+)?$", + REG_EXTENDED | REG_ICASE) == 0); + + prne_init_recon_param(¶m); + param.evt_cb = evt_cb; + prne_init_worker(&wkr); + mbedtls_entropy_init(&entropy); + mbedtls_ctr_drbg_init(&ctr_drbg); + sigemptyset(&ss_term); + sigaddset(&ss_term, SIGTERM); + sigaddset(&ss_term, SIGINT); + + // parse args + if (argc < 3) { + print_help(stderr, args[0]); + ret = 2; + goto END; + } + + if (prne_nstreq(args[1], "-")) { + conf_f = stdin; + } + else { + own_conf_f = true; + conf_f = fopen(args[1], "r"); + + if (conf_f == NULL) { + perror(args[1]); + ret = 1; + goto END; + } + } + + for (int i = 2; i < argc; i += 1) { + uint16_t port; + + if (sscanf(args[i], "%"SCNu16, &port) != 1 || port == 0) { + fprintf(stderr, "*** %s: invalid port value\n", args[i]); + ret = 2; + goto END; + } + prne_assert(prne_alloc_recon_param( + ¶m, + param.blist.cnt, + param.target.cnt, + param.ports.cnt + 1)); + param.ports.arr[param.ports.cnt - 1] = port; + } + + prne_assert(pth_init()); + + // try-catch init + prne_assert(mbedtls_ctr_drbg_seed( + &ctr_drbg, + mbedtls_entropy_func, + &entropy, + NULL, + 0) == 0); + + // parse conf + ret = do_parse_conf(conf_f, ¶m); + if (ret != 0) { + goto END; + } + if (param.target.cnt == 0) { + fprintf(stderr, "*** No target network configured\n"); + ret = 2; + goto END; + } + + // alloc recon + recon = prne_alloc_recon( + &wkr, + &ctr_drbg, + prne_own_recon_param(¶m, false)); + if (recon == NULL) { + perror("prne_alloc_recon()"); + ret = 2; + goto END; + } + wkr.pth = pth_spawn(PTH_ATTR_DEFAULT, wkr.entry, wkr.ctx); + prne_assert(wkr.pth != NULL); + + // wait for termination + prne_assert(sigprocmask(SIG_BLOCK, &ss_term, NULL) == 0); + pth_sigwait(&ss_term, &caught_sig); + sigprocmask(SIG_UNBLOCK, &ss_term, NULL); + + // fin worker + wkr.fin(wkr.ctx); + pth_join(wkr.pth, NULL); + wkr.free_ctx(wkr.ctx); + +END: + // clean up + regfree(&re_entry); + regfree(&re_comment); + regfree(&re_empty); + prne_free_recon_param(¶m); + if (own_conf_f && conf_f != NULL) { + fclose(conf_f); + } + mbedtls_ctr_drbg_free(&ctr_drbg); + mbedtls_entropy_free(&entropy); + + pth_kill(); + + return ret; +} diff --git a/src/proone-rnd.c b/src/proone-rnd.c index b5a1edf..215f930 100644 --- a/src/proone-rnd.c +++ b/src/proone-rnd.c @@ -45,10 +45,10 @@ int main (const int argc, const char **args) { NULL, 0) == 0); { - uint8_t is[64]; + uint8_t is[PRNE_RND_WELL512_SEEDLEN]; prne_assert(mbedtls_ctr_drbg_random(&ctr_drbg, is, sizeof(is)) == 0); - prne_assert(prne_rnd_alloc_well512(&rnd, is, sizeof(is))); + prne_assert(prne_rnd_alloc_well512(&rnd, is)); } arr = prne_calloc(sizeof(uint32_t), max); diff --git a/src/proone.c b/src/proone.c index 623d3b6..75c73f5 100644 --- a/src/proone.c +++ b/src/proone.c @@ -74,7 +74,8 @@ static void alloc_resolv (void) { prne_g.resolv = prne_alloc_resolv( wkr_arr + wkr_cnt, &prne_g.ssl.rnd, - pool4, pool6); + pool4, + pool6); if (prne_g.resolv != NULL) { wkr_cnt += 1; pool4.ownership = false; @@ -333,13 +334,13 @@ static void open_blackhole (void) { } static void delete_myself (const char *arg0) { -#if !defined(PRNE_DEBUG) +#if !PRNE_DEBUG unlink(arg0); #endif } static void disasble_watchdog (void) { -#ifndef PRNE_DEBUG +#if !PRNE_DEBUG static const char *watchdog_paths[] = { "/dev/watchdog", "/dev/misc/watchdog" @@ -1009,7 +1010,7 @@ int main (const int argc, const char **args) { // done with the terminal close(STDIN_FILENO); -#ifndef PRNE_DEBUG +#if !PRNE_DEBUG // Some stupid library can use these close(STDOUT_FILENO); close(STDERR_FILENO); diff --git a/src/recon.c b/src/recon.c new file mode 100644 index 0000000..94b1a2e --- /dev/null +++ b/src/recon.c @@ -0,0 +1,916 @@ +#include "recon.h" +#include "rnd.h" +#include "llist.h" +#include "util_rt.h" +#include "endian.h" +#include "inet.h" + +#include +#include + +#include +#include +#include +#include + +#include +#include +// TODO: Don't use these +#include +#include +#include + + +static const struct timespec RCN_ERR_PAUSE_INT = { 1, 0 }; // 1 s +#define RCN_II_UPDATE_INT_MIN 43200 // 0.5 days +#define RCN_II_UPDATE_INT_VAR 43200 // 0.5 days +#define RCN_SRC_PORT_MIN 1024 +#define RCN_SRC_PORT_VAR 64511 +// 800ms ~ 1200ms tick +#define RCN_SYN_TICK_MIN 800 +#define RCN_SYN_TICK_VAR 400 +// 60 ~ 160 syn packets per tick +static const uint_fast32_t RCN_SYN_PPT_MIN = 60; +static const uint_fast32_t RCN_SYN_PPT_VAR = 100; + +#define RCN_IDX_IPV4 0 +#define RCN_IDX_IPV6 1 +#define RCN_NB_FD 2 + +typedef struct { + uint32_t cur; + uint32_t max; +} rcn_srcaddr_ctr_t; + +typedef struct { + prne_ip_addr_t ep; + uint8_t network[16]; + uint8_t hostmask[16]; + rcn_srcaddr_ctr_t ctr; +} rcn_ifaceinfo_t; + +struct prne_recon { + prne_recon_param_t param; + pth_mutex_t lock; + pth_cond_t cond; + prne_rnd_t rnd; + struct { + struct timespec ii_up; // next subnet update + } ts; + prne_llist_t ii_list; + prne_llist_entry_t *ii_ptr; + size_t t_ptr; + int fd[RCN_NB_FD][2]; + uint32_t seq_mask; + uint16_t s_port; + bool loop; + bool send_ptr; +}; + +static void rcn_main_empty_ii_list (prne_recon_t *ctx) { + prne_llist_entry_t *ent = ctx->ii_list.head; + + while (ent != NULL) { + prne_free(ent->element); + ent = ent->next; + } + prne_llist_clear(&ctx->ii_list); + ctx->ii_ptr = NULL; +} + +static bool rcn_main_good_iface (const struct ifaddrs *ia) { + return + ia->ifa_addr != NULL && + ia->ifa_netmask != NULL && + (ia->ifa_flags & 0x1) && // up + !(ia->ifa_flags & 0x8); // and not loopback +} + +static uint32_t rcn_build_srcaddr4_ctr (const uint8_t *arr) { + return ~prne_recmb_msb32(arr[0], arr[1], arr[2], arr[3]); +} + +static uint32_t rcn_build_srcaddr6_ctr (const uint8_t *arr) { + return ~prne_recmb_msb32(arr[14], arr[13], arr[14], arr[15]); +} + +static bool rcn_main_do_ifaddrs (prne_recon_t *ctx) { + bool ret = false; + struct ifaddrs *ia_arr = NULL, *ia_ent; + struct sockaddr_in *sa4; + struct sockaddr_in6 *sa6; + rcn_ifaceinfo_t *info; + prne_llist_entry_t *ent; + + rcn_main_empty_ii_list(ctx); + + if (getifaddrs(&ia_arr) != 0) { + goto END; + } + + for (ia_ent = ia_arr; ia_ent != NULL; ia_ent = ia_ent->ifa_next) { + if (!rcn_main_good_iface(ia_ent)) { + continue; + } + + switch (ia_ent->ifa_addr->sa_family) { + case AF_INET: + if (ctx->fd[RCN_IDX_IPV4][1] < 0) { + continue; + } + break; + case AF_INET6: + if (ctx->fd[RCN_IDX_IPV6][1] < 0) { + continue; + } + break; + } + + switch (ia_ent->ifa_addr->sa_family) { + case AF_INET6: + sa6 = (struct sockaddr_in6*)ia_ent->ifa_addr; + if (sa6->sin6_scope_id != 0) { + continue; + } + /* fall-through */ + case AF_INET: + ent = prne_llist_append(&ctx->ii_list, NULL); + if (ent == NULL) { + goto END; + } + info = (rcn_ifaceinfo_t*)prne_calloc(sizeof(rcn_ifaceinfo_t), 1); + if (info == NULL) { + goto END; + } + ent->element = info; + break; + default: continue; + } + + switch (ia_ent->ifa_addr->sa_family) { + case AF_INET: + info->ep.ver = PRNE_IPV_4; + sa4 = (struct sockaddr_in*)ia_ent->ifa_addr; + memcpy(info->ep.addr, &sa4->sin_addr, 4); + + sa4 = (struct sockaddr_in*)ia_ent->ifa_netmask; + prne_bitop_and( + info->ep.addr, + (const uint8_t*)&sa4->sin_addr, + info->network, + 4); + prne_bitop_inv((const uint8_t*)&sa4->sin_addr, info->hostmask, 4); + info->ctr.max = rcn_build_srcaddr4_ctr( + (const uint8_t*)&sa4->sin_addr); + break; + case AF_INET6: + info->ep.ver = PRNE_IPV_6; + sa6 = (struct sockaddr_in6*)ia_ent->ifa_addr; + memcpy(info->ep.addr, &sa6->sin6_addr, 16); + + sa6 = (struct sockaddr_in6*)ia_ent->ifa_netmask; + prne_bitop_and( + info->ep.addr, + (const uint8_t*)&sa6->sin6_addr, + info->network, + 16); + prne_bitop_inv((const uint8_t*)&sa6->sin6_addr, info->hostmask, 16); + info->ctr.max = rcn_build_srcaddr6_ctr( + (const uint8_t*)&sa6->sin6_addr); + break; + } + } + + ctx->ii_ptr = ctx->ii_list.head; + ret = true; +END: + if (!ret) { + rcn_main_empty_ii_list(ctx); + } + freeifaddrs(ia_arr); + + return ret; +} + +static prne_ipv_t rcn_main_genaddr_ii ( + prne_recon_t *ctx, + uint8_t *src, + uint8_t *dst) +{ + prne_ipv_t ret = PRNE_IPV_NONE; + rcn_ifaceinfo_t *info; + size_t l; + + while (ctx->ii_ptr != NULL && ret == PRNE_IPV_NONE) { + info = (rcn_ifaceinfo_t*)ctx->ii_ptr->element; + + if (info->ctr.cur >= info->ctr.max) { + prne_free(info); + ctx->ii_ptr = prne_llist_erase(&ctx->ii_list, ctx->ii_ptr); + } + else { + ctx->ii_ptr = ctx->ii_ptr->next; + switch (info->ep.ver) { + case PRNE_IPV_4: l = 4; break; + case PRNE_IPV_6: l = 16; break; + default: abort(); + } + + memcpy(src, info->ep.addr, l); + prne_rnd(&ctx->rnd, dst, l); + prne_bitop_and(dst, info->hostmask, dst, l); + prne_bitop_or(dst, info->network, dst, l); + + info->ctr.cur += 1; + if (memcmp(src, dst, l) != 0) { + ret = info->ep.ver; + } + } + + if (ctx->ii_ptr == NULL) { + ctx->ii_ptr = ctx->ii_list.head; + } + } + + return ret; +} + +static prne_ipv_t rcn_main_genaddr_param ( + prne_recon_t *ctx, + uint8_t *src, + uint8_t *dst) +{ + const prne_recon_network_t *net; + + for (size_t i = 0; i < ctx->param.target.cnt; i += 1) { + ctx->t_ptr = (ctx->t_ptr + 1) % ctx->param.target.cnt; + net = ctx->param.target.arr + ctx->t_ptr; + + switch (net->addr.ver) { + case PRNE_IPV_4: + if (ctx->fd[RCN_IDX_IPV4][1] < 0) { + continue; + } + prne_rnd(&ctx->rnd, dst, 4); + prne_bitop_inv(net->mask, src, 4); // use src as host mask + prne_bitop_and(src, dst, dst, 4); // extract host + prne_bitop_or(net->addr.addr, dst, dst, 4); // combine with network + prne_memzero(src, 4); // let kernel fill this in + return PRNE_IPV_4; + case PRNE_IPV_6: + if (ctx->fd[RCN_IDX_IPV6][1] < 0) { + continue; + } + prne_rnd(&ctx->rnd, dst, 16); + prne_bitop_inv(net->mask, src, 16); // use src as host mask + prne_bitop_and(src, dst, dst, 16); // extract host + prne_bitop_or(net->addr.addr, dst, dst, 16); // combine with network + prne_memzero(src, 16); // let kernel fill this in + return PRNE_IPV_6; + } + } + + return PRNE_IPV_NONE; +} + +static prne_ipv_t rcn_main_gen_addr ( + prne_recon_t *ctx, + uint8_t *src, + uint8_t *dst, + int *snd_flags) +{ + prne_ipv_t ret = PRNE_IPV_NONE; + + ctx->send_ptr = !ctx->send_ptr; + if (ctx->send_ptr) { + ret = rcn_main_genaddr_ii(ctx, src, dst); + if (ret != PRNE_IPV_NONE) { + *snd_flags |= MSG_DONTROUTE; + return ret; + } + } + return rcn_main_genaddr_param(ctx, src, dst); +} + +static bool rcn_main_chk_blist ( + prne_recon_t *ctx, + const prne_ipv_t v, + uint8_t *addr) +{ + const prne_recon_network_t *net; + uint8_t tmp[16]; + size_t l = 0; + + for (size_t i = 0; i < ctx->param.blist.cnt; i += 1) { + net = ctx->param.blist.arr + i; + + if (net->addr.ver != v) { + continue; + } + switch (v) { + case PRNE_IPV_4: l = 4; break; + case PRNE_IPV_6: l = 16; break; + } + + prne_bitop_and(addr, net->mask, tmp, l); + if (memcmp(tmp, net->addr.addr, l) == 0) { + return true; + } + } + + return false; +} + +static void rcn_main_send_syn (prne_recon_t *ctx) { + prne_ipv_t ret; + uint8_t src[16], dst[16]; + uint8_t m_head[prne_op_max(sizeof(struct iphdr), sizeof(struct ipv6hdr))]; + uint8_t m_pkt[sizeof(m_head) + sizeof(struct tcphdr)]; + uint8_t m_sa[prne_op_max( + sizeof(struct sockaddr_in), + sizeof(struct sockaddr_in6))]; + struct iphdr *ih4; + struct ipv6hdr *ih6; + struct sockaddr_in *sa4; + struct sockaddr_in6 *sa6; + socklen_t sl = 0; + struct tcphdr th; + size_t coin, pkt_len = 0; + uint16_t d_port; + int snd_flags = MSG_NOSIGNAL, f_ret, fd; + + ret = rcn_main_gen_addr(ctx, src, dst, &snd_flags); + if (ret == PRNE_IPV_NONE || rcn_main_chk_blist(ctx, ret, dst)) { + return; + } + + prne_memzero(m_head, sizeof(m_head)); + prne_memzero(m_sa, sizeof(m_sa)); + prne_memzero(&th, sizeof(th)); + prne_rnd(&ctx->rnd, (uint8_t*)&coin, sizeof(coin)); + d_port = ctx->param.ports.arr[coin % ctx->param.ports.cnt]; + + th.source = htons(ctx->s_port); + th.dest = htons(d_port); + th.doff = 5; + th.syn = 1; + prne_rnd(&ctx->rnd, (uint8_t*)&th.window, sizeof(th.window)); + th.window = htons(100 + (th.window % (UINT16_MAX - 100))); + + switch (ret) { + case PRNE_IPV_4: + ih4 = (struct iphdr*)m_head; + ih4->version = 4; + ih4->ihl = 5; + // filled in by kernel + // ih4->tot_len = htons(sizeof(struct iphdr) + sizeof(struct tcphdr)); + // let kernel fill this in + // prne_rnd(&ctx->rnd, &ih4->id, sizeof(ih4->id)); + ih4->ttl = 64; + ih4->protocol = IPPROTO_TCP; + memcpy(&ih4->saddr, src, 4); + memcpy(&ih4->daddr, dst, 4); + // filled in by kernel + // ih4->check = htons(rcn_main_ih_chk(m_head, sizeof(struct iphdr))); + + th.seq = + prne_recmb_msb32(dst[0], dst[1], dst[2], dst[3]) ^ + ctx->seq_mask; + th.seq = htonl(th.seq); + th.check = htons(prne_calc_tcp_chksum4( + ih4, + (const uint8_t*)&th, + sizeof(th), + NULL, + 0)); + + memcpy(m_pkt, ih4, sizeof(struct iphdr)); + memcpy(m_pkt + sizeof(struct iphdr), &th, sizeof(struct tcphdr)); + pkt_len = sizeof(struct iphdr) + sizeof(struct tcphdr); + + sa4 = (struct sockaddr_in*)m_sa; + sa4->sin_family = AF_INET; + memcpy(&sa4->sin_addr, dst, 4); + sl = sizeof(struct sockaddr_in); + fd = ctx->fd[RCN_IDX_IPV4][1]; + + if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0 + 1) { + char s_str[INET_ADDRSTRLEN]; + char d_str[INET_ADDRSTRLEN]; + + prne_assert( + inet_ntop(AF_INET, &ih4->saddr, s_str, sizeof(s_str)) && + inet_ntop(AF_INET, &ih4->daddr, d_str, sizeof(d_str))); + prne_dbgpf( + "Send SYN %s:%"PRIu16 " -> %s:%"PRIu16"\n", + s_str, + ntohs(th.source), + d_str, + ntohs(th.dest)); + } + break; + case PRNE_IPV_6: + ih6 = (struct ipv6hdr*)m_head; + ih6->version = 6; + prne_rnd(&ctx->rnd, ih6->flow_lbl, 3); + ih6->payload_len = htons(sizeof(struct tcphdr)); + ih6->nexthdr = IPPROTO_TCP; + ih6->hop_limit = 64; + memcpy(&ih6->saddr, src, 16); + memcpy(&ih6->daddr, dst, 16); + + th.seq = + prne_recmb_msb32(dst[0], dst[1], dst[2], dst[3]) ^ + prne_recmb_msb32(dst[4], dst[5], dst[6], dst[7]) ^ + prne_recmb_msb32(dst[8], dst[9], dst[10], dst[11]) ^ + prne_recmb_msb32(dst[12], dst[13], dst[14], dst[15]) ^ + ctx->seq_mask; + th.seq = htonl(th.seq); + th.check = htons(prne_calc_tcp_chksum6( + ih6, + (const uint8_t*)&th, + sizeof(th), + NULL, + 0)); + + memcpy(m_pkt, ih6, sizeof(struct ipv6hdr)); + memcpy(m_pkt + sizeof(struct ipv6hdr), &th, sizeof(struct tcphdr)); + pkt_len = sizeof(struct ipv6hdr) + sizeof(struct tcphdr); + + sa6 = (struct sockaddr_in6*)m_sa; + sa6->sin6_family = AF_INET6; + memcpy(&sa6->sin6_addr, dst, 16); + sl = sizeof(struct sockaddr_in6); + fd = ctx->fd[RCN_IDX_IPV6][1]; + + if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0 + 1) { + char s_str[INET6_ADDRSTRLEN]; + char d_str[INET6_ADDRSTRLEN]; + + prne_assert( + inet_ntop(AF_INET6, &ih6->saddr, s_str, sizeof(s_str)) && + inet_ntop(AF_INET6, &ih6->daddr, d_str, sizeof(d_str))); + prne_dbgpf( + "Send SYN [%s]:%"PRIu16 " -> [%s]:%"PRIu16"\n", + s_str, + ntohs(th.source), + d_str, + ntohs(th.dest)); + } + break; + } + + f_ret = sendto( + fd, + m_pkt, + pkt_len, + snd_flags, + (struct sockaddr*)m_sa, + sl); + if (f_ret < 0 && PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) { + prne_dbgperr("** SYN sendto()@rcn"); + } +} + +static void rcn_main_recv_syn_tail ( + prne_recon_t *ctx, + const struct tcphdr *th, + const uint32_t exp_ack, + const prne_net_endpoint_t *ep) +{ + if (ntohs(th->dest) == ctx->s_port && + ntohl(th->ack_seq) == exp_ack && + th->ack && th->syn && !th->rst && !th->fin) + { + ctx->param.evt_cb(ep); + } +} + +static void rcn_main_recv_syn4 (prne_recon_t *ctx) { + int f_ret; + uint8_t buf[ + sizeof(struct iphdr) + + 60 + // options + sizeof(struct tcphdr)]; + struct tcphdr th; + struct iphdr ih; + uint32_t exp_ack; + prne_net_endpoint_t ep; + + while (true) { + f_ret = recv( + ctx->fd[RCN_IDX_IPV4][0], + buf, + sizeof(buf), + 0); + if (f_ret < 0) { + if (errno != EAGAIN && + errno != EWOULDBLOCK && + PRNE_DEBUG && + PRNE_VERBOSE >= PRNE_VL_ERR) + { + prne_dbgperr("** SYN recv()@rcn"); + } + break; + } + if ((size_t)f_ret < sizeof(struct iphdr)) + { + continue; + } + memcpy(&ih, buf, sizeof(struct iphdr)); + if (ih.ihl * 4 + sizeof(struct tcphdr) > (size_t)f_ret) { + continue; + } + memcpy(&th, buf + ih.ihl * 4, sizeof(struct tcphdr)); + + prne_memzero(&ep, sizeof(prne_net_endpoint_t)); + ep.addr.ver = PRNE_IPV_4; + memcpy(ep.addr.addr, &ih.saddr, 4); + ep.port = ntohs(th.source); + exp_ack = (ntohl(ih.saddr) ^ ctx->seq_mask) + 1; + rcn_main_recv_syn_tail(ctx, &th, exp_ack, &ep); + } +} + +static void rcn_main_recv_syn6 (prne_recon_t *ctx) { + int f_ret; + uint8_t buf[1024]; + struct ipv6hdr ih; + struct tcphdr th; + size_t ext_pos; + uint8_t next_hdr; + uint32_t exp_ack; + prne_net_endpoint_t ep; + +LOOP: + while (true) { + f_ret = recv( + ctx->fd[RCN_IDX_IPV6][0], + buf, + sizeof(buf), + 0); + if (f_ret < 0) { + if (errno != EAGAIN && + errno != EWOULDBLOCK && + PRNE_DEBUG && + PRNE_VERBOSE >= PRNE_VL_ERR) + { + prne_dbgperr("** SYN recv()@rcn"); + } + break; + } + if ((size_t)f_ret < sizeof(struct ipv6hdr)) + { + continue; + } + memcpy(&ih, buf, sizeof(struct ipv6hdr)); + + ext_pos = sizeof(struct ipv6hdr); + next_hdr = ih.nexthdr; + while (next_hdr != IPPROTO_TCP && ext_pos + 1 > (size_t)f_ret) { + switch (next_hdr) { + case 0: + case 43: + case 60: + if (ext_pos + 2 > (size_t)f_ret) { + goto LOOP; + } + next_hdr = buf[ext_pos]; + ext_pos += buf[ext_pos + 1] * 8 + 8; + break; + case 59: // no next header + default: // can't understand this packet + goto LOOP; + } + } + if ((size_t)f_ret < ext_pos + sizeof(struct tcphdr)) + { + continue; + } + memcpy(&th, buf + ext_pos, sizeof(struct tcphdr)); + + prne_memzero(&ep, sizeof(prne_net_endpoint_t)); + ep.addr.ver = PRNE_IPV_6; + memcpy(ep.addr.addr, &ih.saddr, 16); + ep.port = ntohs(th.source); + exp_ack = + prne_recmb_msb32( + ep.addr.addr[0], + ep.addr.addr[1], + ep.addr.addr[2], + ep.addr.addr[3]) ^ + prne_recmb_msb32( + ep.addr.addr[4], + ep.addr.addr[5], + ep.addr.addr[6], + ep.addr.addr[7]) ^ + prne_recmb_msb32( + ep.addr.addr[8], + ep.addr.addr[9], + ep.addr.addr[10], + ep.addr.addr[11]) ^ + prne_recmb_msb32( + ep.addr.addr[12], + ep.addr.addr[13], + ep.addr.addr[14], + ep.addr.addr[15]) ^ + ctx->seq_mask; + exp_ack += 1; + rcn_main_recv_syn_tail(ctx, &th, exp_ack, &ep); + } +} + +static void rcn_main_recv_syn (prne_recon_t *ctx) { + if (ctx->fd[RCN_IDX_IPV4][0] >= 0) { + rcn_main_recv_syn4(ctx); + } + if (ctx->fd[RCN_IDX_IPV6][0] >= 0) { + rcn_main_recv_syn6(ctx); + } +} + +static void *rcn_main_entry (void *ctx_p) { + prne_recon_t *ctx = (prne_recon_t*)ctx_p; + struct timespec ts_now; + unsigned int syn_cnt, tick_dur; + pth_event_t ev_root = NULL, ev; + pth_time_t to_pth; + struct timespec to_ts, tick_dur_ts; + + while (ctx->loop) { + ts_now = prne_gettime(CLOCK_MONOTONIC); + + // periodic op + if (prne_cmp_timespec(ctx->ts.ii_up, ts_now) <= 0) { + unsigned int n; + + if (rcn_main_do_ifaddrs(ctx)) { + prne_rnd(&ctx->rnd, (uint8_t*)&n, sizeof(n)); + n = RCN_II_UPDATE_INT_MIN + (n % RCN_II_UPDATE_INT_VAR); + ctx->ts.ii_up = prne_add_timespec(ts_now, prne_ms_timespec(n)); + } + else { + ctx->ts.ii_up = prne_add_timespec(ts_now, RCN_ERR_PAUSE_INT); + } + + prne_rnd(&ctx->rnd, (uint8_t*)&n, sizeof(n)); + ctx->s_port = (uint16_t)(RCN_SRC_PORT_MIN + (n % RCN_SRC_PORT_VAR)); + } + + // random + prne_rnd(&ctx->rnd, (uint8_t*)&syn_cnt, sizeof(syn_cnt)); + syn_cnt = RCN_SYN_PPT_MIN + (syn_cnt % RCN_SYN_PPT_VAR); + prne_rnd(&ctx->rnd, (uint8_t*)&tick_dur, sizeof(tick_dur)); + tick_dur = RCN_SYN_TICK_MIN + (tick_dur % RCN_SYN_TICK_VAR); + prne_rnd(&ctx->rnd, (uint8_t*)&ctx->seq_mask, sizeof(ctx->seq_mask)); + + for (unsigned int i = 0; i < syn_cnt; i += 1) { + rcn_main_send_syn(ctx); + } + + ts_now = prne_gettime(CLOCK_MONOTONIC); + tick_dur_ts = prne_ms_timespec(tick_dur); + to_pth = prne_pth_tstimeout(tick_dur_ts); + to_ts = prne_add_timespec(ts_now, tick_dur_ts); + while (ctx->loop) { + ts_now = prne_gettime(CLOCK_MONOTONIC); + if (prne_cmp_timespec(to_ts, ts_now) <= 0) { + break; + } + + // build event + pth_event_free(ev_root, TRUE); + ev_root = pth_event(PTH_EVENT_TIME, to_pth); + prne_assert(ev_root != NULL); + + for (size_t i = 0; i < RCN_NB_FD; i += 1) { + if (ctx->fd[i][0] < 0) { + continue; + } + ev = pth_event( + PTH_EVENT_FD | PTH_UNTIL_FD_READABLE, + ctx->fd[i][0]); + prne_assert(ev != NULL); + pth_event_concat(ev_root, ev, NULL); + } + + prne_dbgtrap(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); + pth_cond_await(&ctx->cond, &ctx->lock, ev_root); + pth_mutex_release(&ctx->lock); + + // process + for (size_t i = 0; i < RCN_NB_FD; i += 1) { + if (ctx->fd[i][0] < 0) { + continue; + } + rcn_main_recv_syn(ctx); + } + } + } + + pth_event_free(ev_root, TRUE); + + return NULL; +} + +static void rcn_free_f (void *ctx_p) { + prne_recon_t *ctx = (prne_recon_t*)ctx_p; + + if (ctx == NULL) { + return; + } + + rcn_main_empty_ii_list(ctx); + + prne_free_rnd(&ctx->rnd); + prne_free_llist(&ctx->ii_list); + prne_close(ctx->fd[RCN_IDX_IPV4][0]); + prne_close(ctx->fd[RCN_IDX_IPV4][1]); + prne_close(ctx->fd[RCN_IDX_IPV6][0]); + prne_close(ctx->fd[RCN_IDX_IPV6][1]); + + prne_free(ctx); +} + +static void rcn_fin_f (void *ctx_p) { + prne_recon_t *ctx = (prne_recon_t*)ctx_p; + + prne_dbgtrap(pth_mutex_acquire(&ctx->lock, FALSE, NULL)); + ctx->loop = false; + pth_cond_notify(&ctx->cond, TRUE); + pth_mutex_release(&ctx->lock); +} + +static void rcn_create_rsck ( + const int af, + const int pp, + int *fd) +{ + fd[0] = socket(AF_PACKET, SOCK_DGRAM, pp); + fd[1] = socket(af, SOCK_RAW, IPPROTO_RAW); + + if (fd[0] < 0 || + fd[1] < 0 || + !prne_sck_fcntl(fd[0]) || + !prne_sck_fcntl(fd[1])) + { + prne_close(fd[0]); + prne_close(fd[1]); + fd[0] = -1; + fd[1] = -1; + } +} + +prne_recon_t *prne_alloc_recon ( + prne_worker_t *wkr, + mbedtls_ctr_drbg_context *ctr_drbg, + const prne_recon_param_t param) +{ + prne_recon_t *ctx = NULL; + int fd[RCN_NB_FD][2] = { + { -1, -1 }, + { -1, -1 } + }; + uint8_t seed[PRNE_RND_WELL512_SEEDLEN]; + + if (param.target.cnt == 0 || + param.ports.cnt == 0 || + param.evt_cb == NULL) + { + errno = EINVAL; + return NULL; + } + + rcn_create_rsck(AF_INET, htons(ETH_P_IP), fd[RCN_IDX_IPV4]); + rcn_create_rsck(AF_INET6, htons(ETH_P_IPV6), fd[RCN_IDX_IPV6]); + if (fd[RCN_IDX_IPV4][0] < 0 && fd[RCN_IDX_IPV6][0] < 0) { + goto ERR; + } + + ctx = (prne_recon_t*)prne_calloc(sizeof(prne_recon_t), 1); + if (ctx == NULL) { + goto ERR; + } + + ctx->param = param; + pth_mutex_init(&ctx->lock); + pth_cond_init(&ctx->cond); + prne_init_rnd(&ctx->rnd); + ctx->loop = true; + + ctx->fd[RCN_IDX_IPV4][0] = fd[RCN_IDX_IPV4][0]; + ctx->fd[RCN_IDX_IPV4][1] = fd[RCN_IDX_IPV4][1]; + ctx->fd[RCN_IDX_IPV6][0] = fd[RCN_IDX_IPV6][0]; + ctx->fd[RCN_IDX_IPV6][1] = fd[RCN_IDX_IPV6][1]; + + if (mbedtls_ctr_drbg_random(ctr_drbg, seed, sizeof(seed)) != 0) { + goto ERR; + } + if (!prne_rnd_alloc_well512(&ctx->rnd, seed)) { + goto ERR; + } + + wkr->ctx = ctx; + wkr->entry = rcn_main_entry; + wkr->fin = rcn_fin_f; + wkr->free_ctx = rcn_free_f; + + return ctx; +ERR: + prne_close(fd[RCN_IDX_IPV4][0]); + prne_close(fd[RCN_IDX_IPV4][1]); + prne_close(fd[RCN_IDX_IPV6][0]); + prne_close(fd[RCN_IDX_IPV6][1]); + rcn_free_f(ctx); + + return NULL; +} + +void prne_init_recon_param (prne_recon_param_t *p) { + prne_memzero(p, sizeof(prne_recon_param_t)); +} + +void prne_free_recon_param (prne_recon_param_t *p) { + if (p == NULL) { + return; + } + + if (p->ownership) { + prne_free(p->blist.arr); + prne_free(p->target.arr); + prne_free(p->ports.arr); + } + prne_memzero(p, sizeof(prne_recon_param_t)); +} + +bool prne_alloc_recon_param ( + prne_recon_param_t *p, + const size_t blist, + const size_t target, + const size_t ports) +{ + bool ret; + + if (p->ownership) { + ret = + prne_own_realloc( + (void**)&p->blist.arr, + &p->ownership, + sizeof(prne_recon_network_t), + &p->blist.cnt, + blist) && + prne_own_realloc( + (void**)&p->target.arr, + &p->ownership, + sizeof(prne_recon_network_t), + &p->target.cnt, + target) && + prne_own_realloc( + (void**)&p->ports.arr, + &p->ownership, + sizeof(uint16_t), + &p->ports.cnt, + ports); + } + else { + prne_recon_param_t ny = *p; + + ret = + prne_own_realloc( + (void**)&ny.blist.arr, + &ny.ownership, + sizeof(prne_recon_network_t), + &ny.blist.cnt, + blist) && + prne_own_realloc( + (void**)&ny.target.arr, + &ny.ownership, + sizeof(prne_recon_network_t), + &ny.target.cnt, + target) && + prne_own_realloc( + (void**)&ny.ports.arr, + &ny.ownership, + sizeof(uint16_t), + &ny.ports.cnt, + ports); + + if (ret) { + *p = ny; + } + else { + prne_free_recon_param(&ny); + } + } + + return ret; +} + +prne_recon_param_t prne_own_recon_param ( + const prne_recon_param_t *p, + const bool ownership) +{ + prne_recon_param_t ret = *p; + ret.ownership = ownership; + return ret; +} diff --git a/src/recon.h b/src/recon.h new file mode 100644 index 0000000..068175f --- /dev/null +++ b/src/recon.h @@ -0,0 +1,48 @@ +#pragma once +#include "pth.h" +#include "protocol.h" + +#include + + +typedef struct prne_recon prne_recon_t; +typedef struct prne_recon_param prne_recon_param_t; +typedef struct prne_recon_network prne_recon_network_t; +typedef void(*prne_recon_evt_ft)(const prne_net_endpoint_t *ep); + +struct prne_recon_network { + prne_ip_addr_t addr; + uint8_t mask[16]; +}; + +struct prne_recon_param { + struct { + prne_recon_network_t *arr; + size_t cnt; + } blist; + struct { + prne_recon_network_t *arr; + size_t cnt; + } target; + struct { + uint16_t *arr; + size_t cnt; + } ports; + prne_recon_evt_ft evt_cb; + bool ownership; +}; + +prne_recon_t *prne_alloc_recon ( + prne_worker_t *wkr, + mbedtls_ctr_drbg_context *ctr_drbg, + const prne_recon_param_t param); +void prne_init_recon_param (prne_recon_param_t *p); +void prne_free_recon_param (prne_recon_param_t *p); +bool prne_alloc_recon_param ( + prne_recon_param_t *p, + const size_t blist, + const size_t target, + const size_t ports); +prne_recon_param_t prne_own_recon_param ( + const prne_recon_param_t *p, + const bool ownership); diff --git a/src/resolv.c b/src/resolv.c index 30fbac6..7935479 100644 --- a/src/resolv.c +++ b/src/resolv.c @@ -1392,24 +1392,12 @@ void prne_resolv_free_ns_pool (prne_resolv_ns_pool_t *pool) { } bool prne_resolv_alloc_ns_pool (prne_resolv_ns_pool_t *pool, const size_t cnt) { - void *ny; - - ny = prne_realloc(pool->ownership ? pool->arr : NULL, sizeof(prne_net_endpoint_t), cnt); - if (ny != NULL) { - if (!pool->ownership) { - memcpy( - ny, - pool->arr, - prne_op_min(pool->cnt, cnt) * sizeof(prne_net_endpoint_t)); - } - pool->arr = (prne_net_endpoint_t*)ny; - pool->cnt = cnt; - pool->ownership = true; - - return true; - } - - return false; + return prne_own_realloc( + (void**)&pool->arr, + &pool->ownership, + sizeof(prne_net_endpoint_t), + &pool->cnt, + cnt); } prne_resolv_ns_pool_t prne_resolv_own_ns_pool(const prne_resolv_ns_pool_t *pool, const bool ownership) { diff --git a/src/rnd.h b/src/rnd.h index 706ebc1..78d99df 100644 --- a/src/rnd.h +++ b/src/rnd.h @@ -3,6 +3,7 @@ #include #include +#define PRNE_RND_WELL512_SEEDLEN 64 struct prne_rnd { void *ctx; @@ -22,5 +23,4 @@ bool prne_rnd (prne_rnd_t *p, uint8_t *buf, const size_t len); */ bool prne_rnd_alloc_well512 ( prne_rnd_t *p, - const uint8_t *is, - const size_t is_len); + const uint8_t *is); diff --git a/src/rnd_well512.c b/src/rnd_well512.c index 5f7b97e..a6bca13 100644 --- a/src/rnd_well512.c +++ b/src/rnd_well512.c @@ -50,16 +50,10 @@ static void rnd_free_well512 (void *p) { bool prne_rnd_alloc_well512 ( prne_rnd_t *p, - const uint8_t *is, - const size_t is_len) + const uint8_t *is) { rnd_well512_ctx_t *ctx; - if (is_len < sizeof(ctx->state)) { - errno = EINVAL; - return false; - } - ctx = (rnd_well512_ctx_t*)prne_calloc(sizeof(rnd_well512_ctx_t), 1); if (ctx == NULL) { return false; diff --git a/src/util_ct.h b/src/util_ct.h index a199b19..767606a 100644 --- a/src/util_ct.h +++ b/src/util_ct.h @@ -2,11 +2,17 @@ #include #include #include -#ifdef PRNE_DEBUG +#if PRNE_DEBUG #include #include #endif +#define PRNE_VL_FATAL 0 +#define PRNE_VL_ERR 1 +#define PRNE_VL_INFO 1 +#define PRNE_VL_WARN 2 +#define PRNE_VL_DBG0 3 + #define PRNE_LIMIT_ENUM(t,x,l) _Static_assert((x) <= (l),"enum overflow: "#t) #define prne_static_assert(expr, msg) _Static_assert((expr), msg) @@ -17,7 +23,7 @@ #define prne_salign_next(x, align) (((x) % (align) == 0) ? (x) : ((x) / (align) + 1) * (align)) #define prne_salign_at(x, align) (((x) % (align) == 0) ? (x) : ((x) / (align)) * (align)) -#ifdef PRNE_DEBUG +#if PRNE_DEBUG #define prne_dbgpf(...) fprintf(stderr, __VA_ARGS__) #define prne_dbgperr(str) perror(str) #define prne_assert(expr) assert(expr) diff --git a/src/util_rt.c b/src/util_rt.c index 24e924d..df12015 100644 --- a/src/util_rt.c +++ b/src/util_rt.c @@ -123,6 +123,32 @@ size_t prne_getpagesize (void) { return (size_t)ret; } +bool prne_own_realloc ( + void **p, + bool *ownership, + const size_t se, + size_t *old, + const size_t req) +{ + void *ny = prne_realloc( + *ownership ? *p : NULL, + se, + req); + + if (req > 0 && ny == NULL) { + return false; + } + + if (!*ownership) { + memcpy(ny, *p, prne_op_min(*old, req) * se); + } + *p = ny; + *old = req; + *ownership = true; + + return true; +} + bool prne_nstreq (const char *a, const char *b) { return strcmp(a == NULL ? "" : a, b == NULL ? "" : b) == 0; } @@ -293,6 +319,19 @@ void prne_uuid_tostr (const uint8_t *in, char *out) { out[ptr] = 0; } +struct timespec prne_add_timespec ( + const struct timespec a, + const struct timespec b) +{ + struct timespec ret; + + ret.tv_nsec = a.tv_nsec + b.tv_nsec; + ret.tv_sec = a.tv_sec + b.tv_sec + (ret.tv_nsec / 1000000000); + ret.tv_nsec %= 1000000000; + + return ret; +} + struct timespec prne_sub_timespec (const struct timespec a, const struct timespec b) { struct timespec ret; @@ -422,3 +461,35 @@ ssize_t prne_geturandom (void *buf, const size_t len) { return ret; } + +void prne_bitop_and ( + const uint8_t *a, + const uint8_t *b, + uint8_t *c, + const size_t len) +{ + for (size_t i = 0; i < len; i += 1) { + c[i] = a[i] & b[i]; + } +} + +void prne_bitop_or ( + const uint8_t *a, + const uint8_t *b, + uint8_t *c, + const size_t len) +{ + for (size_t i = 0; i < len; i += 1) { + c[i] = a[i] | b[i]; + } +} + +void prne_bitop_inv ( + const uint8_t *x, + uint8_t *y, + const size_t len) +{ + for (size_t i = 0; i < len; i += 1) { + y[i] = ~x[i]; + } +} diff --git a/src/util_rt.h b/src/util_rt.h index f44e4ae..3d94bf5 100644 --- a/src/util_rt.h +++ b/src/util_rt.h @@ -30,6 +30,13 @@ char *prne_alloc_str (const size_t len); void prne_free (void *ptr); size_t prne_getpagesize (void); +bool prne_own_realloc ( + void **p, + bool *ownership, + const size_t se, + size_t *old, + const size_t req); + bool prne_nstreq (const char *a, const char *b); size_t prne_nstrlen (const char *s); void prne_rnd_anum_str (mbedtls_ctr_drbg_context *rnd, char *str, const size_t len); @@ -43,6 +50,7 @@ void prne_hex_tochar (const uint_fast8_t in, char *out, const bool upper); bool prne_uuid_fromstr (const char *str, uint8_t *out); void prne_uuid_tostr (const uint8_t *in, char *out); +struct timespec prne_add_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); struct timespec prne_ms_timespec (const long ms); @@ -59,3 +67,18 @@ bool prne_dec_base64_mem (const char *str, const size_t str_len, uint8_t **data, // getrandom polyfill ssize_t prne_geturandom (void *buf, const size_t len); + +void prne_bitop_and ( + const uint8_t *a, + const uint8_t *b, + uint8_t *c, + const size_t len); +void prne_bitop_or ( + const uint8_t *a, + const uint8_t *b, + uint8_t *c, + const size_t len); +void prne_bitop_inv ( + const uint8_t *x, + uint8_t *y, + const size_t len); -- cgit