aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Timber <mieabby@gmail.com>2020-09-14 15:47:30 +0930
committerDavid Timber <mieabby@gmail.com>2020-09-14 15:47:30 +0930
commitf7f7332afafd4f965c5ef1d45cc1c7da9275c6ef (patch)
tree53b8e96d2d070215f0c6ee133cdba58ca93a4138 /src
parentc4160ed41717260b5941e2729c444b8ec051d5f0 (diff)
* 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()
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am40
-rw-r--r--src/data/recon.sample.conf10
-rw-r--r--src/htbt.c2
-rw-r--r--src/inet.c156
-rw-r--r--src/inet.h22
-rw-r--r--src/proone-recon.c291
-rw-r--r--src/proone-rnd.c4
-rw-r--r--src/proone.c9
-rw-r--r--src/recon.c916
-rw-r--r--src/recon.h48
-rw-r--r--src/resolv.c24
-rw-r--r--src/rnd.h4
-rw-r--r--src/rnd_well512.c8
-rw-r--r--src/util_ct.h10
-rw-r--r--src/util_rt.c71
-rw-r--r--src/util_rt.h23
16 files changed, 1592 insertions, 46 deletions
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 <stdint.h>
+#include <stdbool.h>
+#include <stddef.h>
+
+// TODO: don't use these
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+
+
+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 <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <regex.h>
+#include <arpa/inet.h>
+
+#include <mbedtls/entropy.h>
+#include <mbedtls/ctr_drbg.h>
+
+#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 <conf> <port 1> [port 2] ... [port n]\n"
+ "Options:\n"
+ "\t<conf>: Path to config file. Pass \"-\" to read stdin\n"
+ "Config Format: <ENTRY SPEC> <NET SPEC>\n"
+ "\t<ENTRY SPEC>: \"T\" for target or \"BL\" for blacklist\n"
+ "\t<NET SPEC>: <IPv4 or IPv6 Address>/<CIDR>\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(&param);
+ 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(
+ &param,
+ 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, &param);
+ 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(&param, 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(&param);
+ 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 <string.h>
+#include <errno.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <netinet/ip6.h>
+#include <arpa/inet.h>
+
+#include <ifaddrs.h>
+#include <linux/if_ether.h>
+// TODO: Don't use these
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/tcp.h>
+
+
+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 <mbedtls/ctr_drbg.h>
+
+
+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 <stddef.h>
#include <stdbool.h>
+#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 <assert.h>
#include <stdint.h>
#include <stdlib.h>
-#ifdef PRNE_DEBUG
+#if PRNE_DEBUG
#include <stdio.h>
#include <errno.h>
#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);