aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Timber <mieabby@gmail.com>2021-08-17 12:07:24 +1000
committerDavid Timber <mieabby@gmail.com>2021-08-17 12:07:24 +1000
commitaf9f23da9f3ce89353cf06878bf8ab49b405e331 (patch)
treef49c0aaa74ee09ca11c03f0aead5010d41eb18f6 /src
parenta161674bcee21384a73834e3ca16ad3bf1c70cf3 (diff)
Impl full IPv6 support ...
* Use different strategy for discovering IPv6 hosts on the network * Multicast IPv6 packet with bogus destination options to get ICMPv6 responses(type 4, code 2) * Send SYN packets to the hosts responds to the packet to confirm that they have target ports open * Add full scope_id support * Fix potential infinite loop when receiving raw packets
Diffstat (limited to 'src')
-rw-r--r--src/proone-bne.c42
-rw-r--r--src/proone-htbthost.c4
-rw-r--r--src/proone-recon.c11
-rw-r--r--src/protocol.c1
-rw-r--r--src/protocol.h1
-rw-r--r--src/recon.c569
-rw-r--r--src/resolv.c32
7 files changed, 432 insertions, 228 deletions
diff --git a/src/proone-bne.c b/src/proone-bne.c
index 89a5d7f..359b634 100644
--- a/src/proone-bne.c
+++ b/src/proone-bne.c
@@ -10,6 +10,7 @@
#include <fcntl.h>
#include <sys/stat.h>
#include <arpa/inet.h>
+#include <net/if.h>
#include <mbedtls/entropy.h>
@@ -41,6 +42,10 @@ struct {
struct {
struct {
+ char *addr;
+ uint32_t scope_id;
+ } arg;
+ struct {
uint8_t *m;
size_t l;
prne_cred_dict_t ctx;
@@ -102,6 +107,8 @@ static void init_g (void) {
}
static void free_g (void) {
+ prne_free(prog_g.arg.addr);
+ prog_g.arg.addr = NULL;
prne_free_llist(&prog_g.wkr_list);
mbedtls_ctr_drbg_free(&prog_g.ssl.ctr_drbg);
mbedtls_entropy_free(&prog_g.ssl.entropy);
@@ -143,6 +150,31 @@ static void load_str (char **dst, const char *str) {
}
}
+static bool load_addr (const char *addr) {
+ char *p;
+
+ prog_g.arg.addr = prne_redup_str(prog_g.arg.addr, addr);
+ prne_assert(prog_g.arg.addr != NULL);
+
+ p = strrchr(prog_g.arg.addr, '%');
+ if (p != NULL) {
+ *p = 0;
+ p += 1;
+ prog_g.arg.scope_id = if_nametoindex(p);
+
+ if (prog_g.arg.scope_id == 0 &&
+ 1 != sscanf(p, "%"SCNu32, &prog_g.arg.scope_id))
+ {
+ return false;
+ }
+ }
+ else {
+ prog_g.arg.scope_id = 0;
+ }
+
+ return true;
+}
+
static int parse_args (const int argc, char *const*args) {
static const struct option lopts[] = {
{ "cdict", required_argument, 0, 0 },
@@ -216,10 +248,16 @@ static int parse_args (const int argc, char *const*args) {
for (size_t i = 0; i < prog_conf.targets.cnt; i += 1, optind += 1) {
prne_ip_addr_t *p = prog_conf.targets.arr + i;
- if (inet_pton(AF_INET6, args[optind], p->addr)) {
+ if (!load_addr(args[optind])) {
+ fprintf(stderr, "%s: invalid scope id\n", args[optind]);
+ return 2;
+ }
+
+ if (inet_pton(AF_INET6, prog_g.arg.addr, p->addr)) {
p->ver = PRNE_IPV_6;
+ p->scope_id = prog_g.arg.scope_id;
}
- else if (inet_pton(AF_INET, args[optind], p->addr)) {
+ else if (inet_pton(AF_INET, prog_g.arg.addr, p->addr)) {
p->ver = PRNE_IPV_4;
}
else {
diff --git a/src/proone-htbthost.c b/src/proone-htbthost.c
index 106d899..c4f543e 100644
--- a/src/proone-htbthost.c
+++ b/src/proone-htbthost.c
@@ -244,6 +244,8 @@ static bool parse_param (const char *arg) {
prne_net_endpoint_t ep;
size_t pos;
+ prne_memzero(&ep, sizeof(ep));
+
pos = rm[1].rm_eo - rm[1].rm_so;
memcpy(str, arg + rm[1].rm_so, pos);
str[pos] = 0;
@@ -271,6 +273,8 @@ static bool parse_param (const char *arg) {
prne_net_endpoint_t ep;
size_t pos;
+ prne_memzero(&ep, sizeof(ep));
+
pos = rm[1].rm_eo - rm[1].rm_so;
memcpy(str, arg + rm[1].rm_so, rm[1].rm_eo - rm[1].rm_so);
str[pos] = 0;
diff --git a/src/proone-recon.c b/src/proone-recon.c
index 43fe8d5..71ece91 100644
--- a/src/proone-recon.c
+++ b/src/proone-recon.c
@@ -136,21 +136,22 @@ INV_LINE:
static void evt_cb (void *ctx, 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";
+ printf("%s:%"PRIu16"\n", addr_str, ep->port);
break;
case PRNE_IPV_6:
inet_ntop(AF_INET6, ep->addr.addr, addr_str, sizeof(addr_str));
- fmt = "[%s]:%"PRIu16"\n";
+ printf(
+ "[%s%%%"PRIu32"]:%"PRIu16"\n",
+ addr_str,
+ ep->addr.scope_id,
+ ep->port);
break;
default: abort();
}
-
- printf(fmt, addr_str, ep->port);
}
int main (const int argc, const char **args) {
diff --git a/src/protocol.c b/src/protocol.c
index 5aaccc2..d2bf53d 100644
--- a/src/protocol.c
+++ b/src/protocol.c
@@ -125,6 +125,7 @@ void prne_net_ep_tosin6 (
struct sockaddr_in6 *out)
{
memcpy(&out->sin6_addr, ep->addr.addr, 16);
+ out->sin6_scope_id = ep->addr.scope_id;
out->sin6_family = AF_INET6;
out->sin6_port = htons(ep->port);
}
diff --git a/src/protocol.h b/src/protocol.h
index 822b92a..4fecda5 100644
--- a/src/protocol.h
+++ b/src/protocol.h
@@ -81,6 +81,7 @@ prne_static_assert(
struct prne_ip_addr {
uint8_t addr[16];
prne_ipv_t ver;
+ uint32_t scope_id;
};
struct prne_net_endpoint {
diff --git a/src/recon.c b/src/recon.c
index b7a334c..cbdfcd8 100644
--- a/src/recon.c
+++ b/src/recon.c
@@ -39,26 +39,22 @@ static const struct timespec RCN_ERR_PAUSE_INT = { 10, 0 }; // 10 s
// 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_ICMPV6_PING_CNT 4
+#define RCN_IPV6_PROBE_CNT 4
#define RCN_IDX_IPV4 0
#define RCN_IDX_IPV6 1
#define RCN_NB_FD 2
-static const uint8_t RCN_ICMP_ECHO_DATA[] = {
- 'O', 'I', '!', ' ', 'T', 'h', 'e', ' ',
- 'i', 'n', 't', 'e', 'r', 'n', 'e', 't',
- ' ', 'i', 's', ' ', 'b', 'e', 't', 't',
- 'e', 'r', ' ', 'o', 'f', 'f', ' ', 'w',
- 'i', 't', 'h', 'o', 'u', 't', ' ', 't',
- 'h', 'i', 's', ' ', 'd', 'e', 'v', 'i',
- 'c', 'e', '.', '@', '#', '$', '%', '^'
-};
-static const uint8_t RCN_ICMP_ECHO_DST[] = {
+static const uint8_t RCN_IPV6_DST_LL[] = {
0xff, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01
};
-prne_static_assert(sizeof(RCN_ICMP_ECHO_DST) == 16, "RCN_ICMP_ECHO_DST");
+prne_static_assert(sizeof(RCN_IPV6_DST_LL) == 16, "RCN_IPV6_DST_LL");
+static const uint8_t RCN_ICMP_ECHO_DATA[] = {
+ ' ', '!', '\"', '#', '$', '%', '&', '\'',
+ '(', ')', '*', '+', ',', '-', '.',
+ '/', '0', '1', '2', '3', '4', '5', '6', '7'
+};
typedef struct {
uint32_t cur;
@@ -78,6 +74,7 @@ typedef struct {
} rcn_v6ifaceinfo_t;
struct prne_recon {
+ uint8_t buf[1504]; // typical MTU aligned to 8 bytes
prne_recon_param_t param;
pth_mutex_t lock;
pth_cond_t cond;
@@ -90,12 +87,13 @@ struct prne_recon {
prne_llist_entry_t *ptr;
} v4_ii;
struct {
- rcn_v6ifaceinfo_t *arr;
+ rcn_v6ifaceinfo_t *arr; // sorted by addr
size_t cnt;
} v6_ii;
size_t t_ptr;
size_t ping_cnt;
int fd[RCN_NB_FD][2];
+ struct timespec ts_now;
uint8_t v6_saddr[16];
uint8_t v4_saddr[4];
uint32_t seq_mask;
@@ -104,6 +102,13 @@ struct prne_recon {
bool send_ptr;
};
+static int rcn_v4ii_cmp_asc (const void *a, const void *b) {
+ return memcmp(
+ ((rcn_v6ifaceinfo_t*)a)->addr,
+ ((rcn_v6ifaceinfo_t*)b)->addr,
+ 16);
+}
+
static void rcn_main_empty_v4_ii (prne_recon_t *ctx) {
prne_llist_entry_t *ent = ctx->v4_ii.list.head;
@@ -257,6 +262,12 @@ static bool rcn_main_do_ifaddrs (prne_recon_t *ctx) {
v6arr = NULL;
v6cnt = 0;
+ qsort(
+ ctx->v6_ii.arr,
+ ctx->v6_ii.cnt,
+ sizeof(rcn_v6ifaceinfo_t),
+ rcn_v4ii_cmp_asc);
+
ret = true;
END:
freeifaddrs(ia);
@@ -266,6 +277,29 @@ END:
return ret;
}
+static uint32_t rcn_main_get_iiv6_scope_id (
+ prne_recon_t *ctx,
+ const uint8_t *addr)
+{
+ rcn_v6ifaceinfo_t key;
+ const rcn_v6ifaceinfo_t *found;
+
+ // Because recvfrom() does not return scope_id ...
+ memcpy(key.addr, addr, 16);
+ key.scope_id = 0;
+ found = (const rcn_v6ifaceinfo_t*)bsearch(
+ &key,
+ ctx->v6_ii.arr,
+ ctx->v6_ii.cnt,
+ sizeof(rcn_v6ifaceinfo_t),
+ rcn_v4ii_cmp_asc);
+
+ if (found == NULL) {
+ return 0;
+ }
+ return found->scope_id;
+}
+
static bool rcn_main_genaddr_ii_4 (
prne_recon_t *ctx,
uint8_t *src,
@@ -435,11 +469,19 @@ static bool rcn_main_chk_blist (
return false;
}
-static void rcn_main_send_syn (prne_recon_t *ctx) {
- prne_ipv_t ret;
- uint8_t src[16], dst[16];
+static bool rcn_main_send_syn (
+ prne_recon_t *ctx,
+ const prne_ipv_t ipv,
+ const uint8_t *src,
+ const uint8_t *dst,
+ const uint32_t dst_scope,
+ const int snd_flags)
+{
+ prne_static_assert(
+ sizeof(ctx->buf) >= 40 + sizeof(struct tcphdr),
+ "buffer short for tcpv4");
+ bool ret;
uint8_t m_head[prne_op_max(sizeof(prne_iphdr4_t), sizeof(prne_iphdr6_t))];
- uint8_t m_pkt[40 + sizeof(struct tcphdr)];
uint8_t m_sa[prne_op_max(
sizeof(struct sockaddr_in),
sizeof(struct sockaddr_in6))];
@@ -449,14 +491,9 @@ static void rcn_main_send_syn (prne_recon_t *ctx) {
struct sockaddr_in6 *sa6;
socklen_t sl = 0;
struct tcphdr th;
- size_t coin, pkt_len = 0;
+ size_t coin, pkt_len;
uint16_t d_port;
- int snd_flags = MSG_NOSIGNAL, f_ret, fd = -1;
-
- ret = rcn_main_gen_addr(ctx, src, dst, &snd_flags);
- if (ret == PRNE_IPV_NONE || rcn_main_chk_blist(ctx, ret, dst)) {
- return;
- }
+ int f_ret, fd = -1;
prne_memzero(m_head, sizeof(m_head));
prne_memzero(m_sa, sizeof(m_sa));
@@ -471,7 +508,7 @@ static void rcn_main_send_syn (prne_recon_t *ctx) {
prne_rnd(&ctx->rnd, (uint8_t*)&th.window, sizeof(th.window));
th.window = htons(100 + (th.window % (UINT16_MAX - 100)));
- switch (ret) {
+ switch (ipv) {
case PRNE_IPV_4:
ih4 = (prne_iphdr4_t*)m_head;
ih4->ihl = 5;
@@ -496,8 +533,8 @@ static void rcn_main_send_syn (prne_recon_t *ctx) {
NULL,
0));
- prne_ser_iphdr4(m_pkt, ih4);
- memcpy(m_pkt + 20, &th, sizeof(struct tcphdr));
+ prne_ser_iphdr4(ctx->buf, ih4);
+ memcpy(ctx->buf + 20, &th, sizeof(struct tcphdr));
pkt_len = 20 + sizeof(struct tcphdr);
sa4 = (struct sockaddr_in*)m_sa;
@@ -547,13 +584,14 @@ static void rcn_main_send_syn (prne_recon_t *ctx) {
NULL,
0));
- prne_ser_iphdr6(m_pkt, ih6);
- memcpy(m_pkt + 40, &th, sizeof(struct tcphdr));
+ prne_ser_iphdr6(ctx->buf, ih6);
+ memcpy(ctx->buf + 40, &th, sizeof(struct tcphdr));
pkt_len = 40 + sizeof(struct tcphdr);
sa6 = (struct sockaddr_in6*)m_sa;
sa6->sin6_family = AF_INET6;
memcpy(&sa6->sin6_addr, dst, 16);
+ sa6->sin6_scope_id = dst_scope;
sl = sizeof(struct sockaddr_in6);
fd = ctx->fd[RCN_IDX_IPV6][1];
@@ -565,38 +603,64 @@ static void rcn_main_send_syn (prne_recon_t *ctx) {
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",
+ "Send SYN [%s]:%"PRIu16 " -> [%s%%%"PRIu32"]:%"PRIu16"\n",
s_str,
ntohs(th.source),
d_str,
+ dst_scope,
ntohs(th.dest));
}
break;
+ default: abort();
}
f_ret = sendto(
fd,
- m_pkt,
+ ctx->buf,
pkt_len,
- snd_flags,
+ snd_flags | MSG_NOSIGNAL,
(struct sockaddr*)m_sa,
sl);
- if (f_ret < 0 && PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) {
- prne_dbgperr("** SYN sendto()@rcn");
+ prne_assert(f_ret != 0);
+ ret = f_ret > 0;
+
+ if (!ret) {
+ if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) {
+ prne_dbgperr("** SYN sendto()@rcn");
+ }
+ }
+ return ret;
+}
+
+static void rcn_main_do_syn (prne_recon_t *ctx) {
+ prne_ipv_t ret;
+ uint8_t src[16], dst[16];
+ int snd_flags = 0;
+
+ ret = rcn_main_gen_addr(ctx, src, dst, &snd_flags);
+ if (ret == PRNE_IPV_NONE || rcn_main_chk_blist(ctx, ret, dst)) {
+ return;
}
+ rcn_main_send_syn(ctx, ret, src, dst, 0, snd_flags);
}
-static void rcn_main_send_icmpv6_from (
+// RFC7707 Section 4.3
+static void rcn_main_send_v6probe_from (
prne_recon_t *ctx,
const rcn_v6ifaceinfo_t *from)
{
+#define PKT_LEN\
+ 40 + /* IPv6 header */\
+ 8 + /* Malicious options */\
+ sizeof(struct icmp6_hdr) + /* Legit ICMPv6 that shouldn't be processed */\
+ sizeof(RCN_ICMP_ECHO_DATA) /* ECHO data */
+
+ prne_static_assert(
+ sizeof(ctx->buf) >= PKT_LEN,
+ "buffer short for v6prove");
prne_iphdr6_t iph;
struct icmp6_hdr icmph;
- uint8_t m_pkt[
- 40 +
- sizeof(struct icmp6_hdr) +
- sizeof(RCN_ICMP_ECHO_DATA)];
- uint8_t *p = m_pkt;
+ uint8_t *p = ctx->buf;
struct sockaddr_in6 sa;
int f_ret;
@@ -605,14 +669,14 @@ static void rcn_main_send_icmpv6_from (
prne_memzero(&sa, sizeof(sa));
sa.sin6_family = AF_INET6;
- memcpy(&sa.sin6_addr, RCN_ICMP_ECHO_DST, 16);
+ memcpy(&sa.sin6_addr, RCN_IPV6_DST_LL, 16);
sa.sin6_scope_id = from->scope_id;
- iph.payload_len = sizeof(struct icmp6_hdr) + sizeof(RCN_ICMP_ECHO_DATA);
+ iph.payload_len = 8 + sizeof(struct icmp6_hdr) + sizeof(RCN_ICMP_ECHO_DATA);
iph.next_hdr = IPPROTO_ICMPV6;
iph.hop_limit = 1;
memcpy(iph.saddr, from->addr, 16);
- memcpy(iph.daddr, RCN_ICMP_ECHO_DST, 16);
+ memcpy(iph.daddr, RCN_IPV6_DST_LL, 16);
icmph.icmp6_type = ICMP6_ECHO_REQUEST;
icmph.icmp6_id = htons((uint16_t)ctx->seq_mask);
@@ -622,8 +686,18 @@ static void rcn_main_send_icmpv6_from (
sizeof(icmph),
RCN_ICMP_ECHO_DATA,
sizeof(RCN_ICMP_ECHO_DATA)));
+
+ iph.next_hdr = IPPROTO_DSTOPTS;
prne_ser_iphdr6(p, &iph);
p += 40;
+// https://www.iana.org/assignments/ipv6-parameters/ipv6-parameters.xhtml
+// RFC4727
+ p[0] = IPPROTO_ICMPV6;
+ p[1] = 0;
+ p[2] = 0x9e;
+ p[3] = 4;
+ prne_rnd(&ctx->rnd, p + 4, 4);
+ p += 8;
memcpy(p, &icmph, sizeof(icmph));
p += sizeof(icmph);
memcpy(p, RCN_ICMP_ECHO_DATA, sizeof(RCN_ICMP_ECHO_DATA));
@@ -637,7 +711,8 @@ static void rcn_main_send_icmpv6_from (
inet_ntop(AF_INET6, iph.saddr, s_str, sizeof(s_str)) &&
inet_ntop(AF_INET6, iph.daddr, d_str, sizeof(d_str)));
prne_dbgpf(
- "Send ICMPv6 ECHO [%s%%%"PRIu32"] -> [%s] id=%"PRIu16" seq=%"PRIu16"\n",
+ "Send bogus ICMPv6 ECHO [%s%%%"PRIu32"] -> "
+ "[%s] id=%"PRIu16" seq=%"PRIu16"\n",
s_str,
from->scope_id,
d_str,
@@ -647,90 +722,111 @@ static void rcn_main_send_icmpv6_from (
f_ret = sendto(
ctx->fd[RCN_IDX_IPV6][1],
- m_pkt,
- sizeof(m_pkt),
+ ctx->buf,
+ PKT_LEN,
MSG_NOSIGNAL,
(struct sockaddr*)&sa,
sizeof(sa));
if (f_ret < 0 && PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) {
prne_dbgperr("** ICMPv6 sendto()@rcn");
}
+#undef PKT_LEN
}
static void rcn_main_send_icmpv6 (prne_recon_t *ctx) {
for (size_t i = 0; i < ctx->v6_ii.cnt; i += 1) {
- rcn_main_send_icmpv6_from(ctx, ctx->v6_ii.arr + i);
+ rcn_main_send_v6probe_from(ctx, ctx->v6_ii.arr + i);
}
}
static void rcn_main_recv_syn_tail (
prne_recon_t *ctx,
+ const uint8_t *daddr,
const struct tcphdr *th,
const uint32_t exp_ack,
- const prne_net_endpoint_t *ep)
+ 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)
{
+ if (ep->addr.ver == PRNE_IPV_6) {
+ ep->addr.scope_id = rcn_main_get_iiv6_scope_id(ctx, daddr);
+ }
ctx->param.evt_cb(ctx->param.cb_ctx, ep);
}
}
-static void rcn_main_recv_4 (prne_recon_t *ctx) {
+static bool rcn_main_recv_4 (prne_recon_t *ctx) {
+ prne_static_assert(
+ sizeof(ctx->buf) >= 20 + 60/*options*/ + sizeof(struct tcphdr),
+ "buffer short for tcpv4");
ssize_t f_ret;
- uint8_t buf[
- 20 +
- 60 + // options
- sizeof(struct tcphdr)];
struct tcphdr th;
prne_iphdr4_t 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 (f_ret < 20) {
- continue;
- }
- prne_dser_iphdr4(buf, &ih);
- if (ih.ihl * 4 + sizeof(struct tcphdr) > (size_t)f_ret) {
- continue;
+ f_ret = recv(
+ ctx->fd[RCN_IDX_IPV4][0],
+ ctx->buf,
+ sizeof(ctx->buf),
+ 0);
+ if (f_ret < 0) {
+ if (errno != EAGAIN &&
+ errno != EWOULDBLOCK &&
+ PRNE_DEBUG &&
+ PRNE_VERBOSE >= PRNE_VL_ERR)
+ {
+ prne_dbgperr("** recv()@rcn");
}
- 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 = prne_recmb_msb32(
- ih.saddr[0],
- ih.saddr[1],
- ih.saddr[2],
- ih.saddr[3]) ^
- ctx->seq_mask;
- exp_ack += 1;
- rcn_main_recv_syn_tail(ctx, &th, exp_ack, &ep);
+ return false;
+ }
+ if (f_ret < 20) {
+ return true;
+ }
+ prne_dser_iphdr4(ctx->buf, &ih);
+ if (ih.ihl * 4 + sizeof(struct tcphdr) > (size_t)f_ret) {
+ return true;
}
+ memcpy(&th, ctx->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 = prne_recmb_msb32(
+ ih.saddr[0],
+ ih.saddr[1],
+ ih.saddr[2],
+ ih.saddr[3]) ^
+ ctx->seq_mask;
+ exp_ack += 1;
+ rcn_main_recv_syn_tail(ctx, ih.daddr, &th, exp_ack, &ep);
+
+ return true;
}
-static void rcn_main_recv_6 (prne_recon_t *ctx) {
+static void rcn_main_recv_6_icmp_tail (
+ prne_recon_t *ctx,
+ const prne_iphdr6_t *ih)
+{
+ rcn_main_send_syn(
+ ctx,
+ PRNE_IPV_6,
+ ih->daddr,
+ ih->saddr,
+ rcn_main_get_iiv6_scope_id(ctx, ih->daddr),
+ MSG_DONTROUTE);
+}
+
+static bool rcn_main_recv_6 (prne_recon_t *ctx) {
+ prne_static_assert(
+ sizeof(ctx->buf) >= 40 + prne_op_max(
+ sizeof(struct tcphdr),
+ sizeof(struct icmp6_hdr)),
+ "buffer short for tcpv6");
ssize_t f_ret;
- uint8_t buf[1024];
prne_iphdr6_t ih;
uint8_t m_hdr[prne_op_max(
sizeof(struct tcphdr),
@@ -742,140 +838,190 @@ static void rcn_main_recv_6 (prne_recon_t *ctx) {
uint32_t exp_ack;
prne_net_endpoint_t ep;
size_t data_len;
- uint8_t *p = buf;
+ uint8_t *p = ctx->buf;
+ uint32_t pptr;
prne_memzero(&ep, sizeof(prne_net_endpoint_t));
ep.addr.ver = PRNE_IPV_6;
-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 (f_ret < 40) {
- continue;
- }
- prne_dser_iphdr6(buf, &ih);
-
- ext_pos = 40;
- next_hdr = ih.next_hdr;
- // skip ext headers
- while (next_hdr != IPPROTO_TCP && next_hdr != IPPROTO_ICMPV6) {
- switch (next_hdr) {
- case 0:
- case 43:
- case 60:
- if (ext_pos + 1 >= (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 parse this packet
- goto LOOP;
- }
+ f_ret = recv(
+ ctx->fd[RCN_IDX_IPV6][0],
+ ctx->buf,
+ sizeof(ctx->buf),
+ 0);
+ if (f_ret < 0) {
+ if (errno != EAGAIN &&
+ errno != EWOULDBLOCK &&
+ PRNE_DEBUG &&
+ PRNE_VERBOSE >= PRNE_VL_ERR)
+ {
+ prne_dbgperr("** SYN recv()@rcn");
}
+ return false;
+ }
+ if (f_ret < 40) {
+ return true;
+ }
+ prne_dser_iphdr6(ctx->buf, &ih);
+
+ if (memcmp(ih.saddr, ih.daddr, 16) == 0) {
+ return true;
+ }
- memcpy(ep.addr.addr, ih.saddr, 16);
- p += ext_pos;
+ ext_pos = 40;
+ next_hdr = ih.next_hdr;
+ // skip ext headers
+ while (next_hdr != IPPROTO_TCP && next_hdr != IPPROTO_ICMPV6) {
switch (next_hdr) {
- case IPPROTO_TCP:
- if ((size_t)f_ret < ext_pos + sizeof(struct tcphdr)) {
- continue;
+ case 0:
+ case 43:
+ case 60:
+ if (ext_pos + 1 >= (size_t)f_ret) {
+ return true;
}
- memcpy(m_hdr, p, sizeof(struct tcphdr));
- p += sizeof(struct tcphdr);
- th = (struct tcphdr*)m_hdr;
-
- 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);
+ next_hdr = ctx->buf[ext_pos];
+ ext_pos += ctx->buf[ext_pos + 1] * 8 + 8;
break;
- case IPPROTO_ICMPV6:
- if ((size_t)f_ret < ext_pos + sizeof(struct icmp6_hdr)) {
- continue;
- }
- memcpy(m_hdr, p, sizeof(struct icmp6_hdr));
- p += sizeof(struct icmp6_hdr);
- icmph = (struct icmp6_hdr*)m_hdr;
- data_len = f_ret - ext_pos - sizeof(struct icmp6_hdr);
-
- if (memcmp(ih.saddr, ih.daddr, 16) == 0 ||
- icmph->icmp6_type != ICMP6_ECHO_REPLY ||
- icmph->icmp6_code != 0 ||
+ case 59: // no next header
+ default: // can't parse this packet
+ return true;
+ }
+ }
+
+ memcpy(ep.addr.addr, ih.saddr, 16);
+ p += ext_pos;
+ switch (next_hdr) {
+ case IPPROTO_TCP:
+ if ((size_t)f_ret < ext_pos + sizeof(struct tcphdr)) {
+ return true;
+ }
+ memcpy(m_hdr, p, sizeof(struct tcphdr));
+ p += sizeof(struct tcphdr);
+ th = (struct tcphdr*)m_hdr;
+
+ 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, ih.daddr, th, exp_ack, &ep);
+ break;
+ case IPPROTO_ICMPV6:
+ if ((size_t)f_ret < ext_pos + sizeof(struct icmp6_hdr)) {
+ return true;
+ }
+ memcpy(m_hdr, p, sizeof(struct icmp6_hdr));
+ p += sizeof(struct icmp6_hdr);
+ icmph = (struct icmp6_hdr*)m_hdr;
+ data_len = f_ret - ext_pos - sizeof(struct icmp6_hdr);
+
+ switch (icmph->icmp6_type) {
+ case ICMP6_ECHO_REPLY:
+ if (icmph->icmp6_code != 0 ||
ntohs(icmph->icmp6_id) != (uint16_t)ctx->seq_mask ||
ntohs(icmph->icmp6_seq) != 0 ||
data_len != sizeof(RCN_ICMP_ECHO_DATA) ||
memcmp(p, RCN_ICMP_ECHO_DATA, sizeof(RCN_ICMP_ECHO_DATA)) != 0)
{
- continue;
+ return true;
}
- else {
- ep.port = 0;
- ctx->param.evt_cb(ctx->param.cb_ctx, &ep);
+ // this node shouldn't have processed this packet, but we'll accept
+ if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_WARN) {
+ char s_str[INET6_ADDRSTRLEN];
+ char d_str[INET6_ADDRSTRLEN];
+
+ prne_assert(
+ inet_ntop(AF_INET6, ih.saddr, s_str, sizeof(s_str)) &&
+ inet_ntop(AF_INET6, ih.daddr, d_str, sizeof(d_str)));
+ prne_dbgpf(
+ "Bad IPv6 implementation! [%s] -> [%s]\n",
+ s_str,
+ d_str);
}
+
+ rcn_main_recv_6_icmp_tail(ctx, &ih);
+ break;
+ case ICMP6_PARAM_PROB:
+ pptr = ntohl(icmph->icmp6_pptr);
+ if (icmph->icmp6_code != ICMP6_PARAMPROB_OPTION ||
+ data_len <= pptr ||
+ p[pptr] != 0x9e)
+ {
+ return true;
+ }
+ if (PRNE_DEBUG && PRNE_VERBOSE >= PRNE_VL_DBG0) {
+ char s_str[INET6_ADDRSTRLEN];
+ char d_str[INET6_ADDRSTRLEN];
+
+ prne_assert(
+ inet_ntop(AF_INET6, ih.saddr, s_str, sizeof(s_str)) &&
+ inet_ntop(AF_INET6, ih.daddr, d_str, sizeof(d_str)));
+ prne_dbgpf(
+ "ICMP 4,2 [%s] -> [%s]\n",
+ s_str,
+ d_str);
+ }
+
+ rcn_main_recv_6_icmp_tail(ctx, &ih);
break;
}
+ break;
}
+
+ return true;
}
-static void rcn_main_recv (prne_recon_t *ctx) {
+static bool rcn_main_recv (prne_recon_t *ctx) {
+ bool ret[2];
+
if (ctx->fd[RCN_IDX_IPV4][0] >= 0) {
- rcn_main_recv_4(ctx);
+ ret[0] = rcn_main_recv_4(ctx);
+ }
+ else {
+ ret[0] = false;
}
if (ctx->fd[RCN_IDX_IPV6][0] >= 0) {
- rcn_main_recv_6(ctx);
+ ret[1] = rcn_main_recv_6(ctx);
+ }
+ else {
+ ret[1] = false;
}
+
+ return ret[0] || ret[1];
}
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;
+ unsigned int i, syn_cnt, tick_dur;
pth_event_t ev_root = NULL, ev;
pth_time_t to_pth;
struct timespec to_ts, tick_dur_ts;
+LOOP:
while (ctx->loop) {
- ts_now = prne_gettime(CLOCK_MONOTONIC);
+ ctx->ts_now = prne_gettime(CLOCK_MONOTONIC);
// periodic op
- if (prne_cmp_timespec(ctx->ts.ii_up, ts_now) <= 0) {
+ if (prne_cmp_timespec(ctx->ts.ii_up, ctx->ts_now) <= 0) {
unsigned long n;
rcn_main_update_saddr(ctx);
@@ -883,10 +1029,14 @@ static void *rcn_main_entry (void *ctx_p) {
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));
+ ctx->ts.ii_up = prne_add_timespec(
+ ctx->ts_now,
+ prne_ms_timespec(n));
}
else {
- ctx->ts.ii_up = prne_add_timespec(ts_now, RCN_ERR_PAUSE_INT);
+ ctx->ts.ii_up = prne_add_timespec(
+ ctx->ts_now,
+ RCN_ERR_PAUSE_INT);
}
prne_rnd(&ctx->rnd, (uint8_t*)&n, sizeof(n));
@@ -901,27 +1051,19 @@ static void *rcn_main_entry (void *ctx_p) {
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);
+ for (i = 0; i < syn_cnt; i += 1) {
+ rcn_main_do_syn(ctx);
}
- if (ctx->ping_cnt < RCN_ICMPV6_PING_CNT) {
+ if (ctx->ping_cnt < RCN_IPV6_PROBE_CNT) {
rcn_main_send_icmpv6(ctx);
ctx->ping_cnt += 1;
- if (ctx->ping_cnt >= RCN_ICMPV6_PING_CNT) {
- rcn_main_empty_v6_ii(ctx);
- }
}
- ts_now = prne_gettime(CLOCK_MONOTONIC);
+ 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);
+ to_ts = prne_add_timespec(ctx->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);
@@ -943,7 +1085,24 @@ static void *rcn_main_entry (void *ctx_p) {
pth_mutex_release(&ctx->lock);
// process
- rcn_main_recv(ctx);
+ i = 0;
+ do {
+ // this loop is to prevent the thread starving other threads
+ // because a continuous flow of packets could keep the loop
+ // going forever
+ ctx->ts_now = prne_gettime(CLOCK_MONOTONIC);
+ if (prne_cmp_timespec(to_ts, ctx->ts_now) <= 0) {
+ goto LOOP;
+ }
+
+ i += 1;
+ if (i % syn_cnt == 0) {
+ i = 0;
+ pth_yield(NULL);
+ }
+ // the thread will wait on event when no packet has been
+ // received. i.e. rcn_main_recv() returns false
+ } while (ctx->loop && rcn_main_recv(ctx));
}
}
diff --git a/src/resolv.c b/src/resolv.c
index 40e789a..4b85a54 100644
--- a/src/resolv.c
+++ b/src/resolv.c
@@ -72,14 +72,14 @@ struct prne_resolv {
};
static prne_net_endpoint_t RESOLV_DEF_IPV4_EP_ARR[] = {
- { { { PRNE_RESOLV_NS_IPV4_GOOGLE_A }, PRNE_IPV_4 }, 853 },
- { { { PRNE_RESOLV_NS_IPV4_GOOGLE_B }, PRNE_IPV_4 }, 853 },
- { { { PRNE_RESOLV_NS_IPV4_CLOUDFLARE_A }, PRNE_IPV_4 }, 853 },
- { { { PRNE_RESOLV_NS_IPV4_CLOUDFLARE_B }, PRNE_IPV_4 }, 853 },
- { { { PRNE_RESOLV_NS_IPV4_QUAD9_A }, PRNE_IPV_4 }, 853 },
- { { { PRNE_RESOLV_NS_IPV4_QUAD9_B }, PRNE_IPV_4 }, 853 },
- { { { PRNE_RESOLV_NS_IPV4_CLEANBROWSING_A }, PRNE_IPV_4 }, 853 },
- { { { PRNE_RESOLV_NS_IPV4_CLEANBROWSING_B }, PRNE_IPV_4 }, 853 }
+ { { { PRNE_RESOLV_NS_IPV4_GOOGLE_A }, PRNE_IPV_4, 0 }, 853 },
+ { { { PRNE_RESOLV_NS_IPV4_GOOGLE_B }, PRNE_IPV_4, 0 }, 853 },
+ { { { PRNE_RESOLV_NS_IPV4_CLOUDFLARE_A }, PRNE_IPV_4, 0 }, 853 },
+ { { { PRNE_RESOLV_NS_IPV4_CLOUDFLARE_B }, PRNE_IPV_4, 0 }, 853 },
+ { { { PRNE_RESOLV_NS_IPV4_QUAD9_A }, PRNE_IPV_4, 0 }, 853 },
+ { { { PRNE_RESOLV_NS_IPV4_QUAD9_B }, PRNE_IPV_4, 0 }, 853 },
+ { { { PRNE_RESOLV_NS_IPV4_CLEANBROWSING_A }, PRNE_IPV_4, 0 }, 853 },
+ { { { PRNE_RESOLV_NS_IPV4_CLEANBROWSING_B }, PRNE_IPV_4, 0 }, 853 }
};
const prne_resolv_ns_pool_t PRNE_RESOLV_DEF_IPV4_POOL = {
@@ -89,14 +89,14 @@ const prne_resolv_ns_pool_t PRNE_RESOLV_DEF_IPV4_POOL = {
};
static prne_net_endpoint_t RESOLV_DEF_IPV6_EP_ARR[] = {
- { { { PRNE_RESOLV_NS_IPV6_GOOGLE_A }, PRNE_IPV_6 }, 853 },
- { { { PRNE_RESOLV_NS_IPV6_GOOGLE_B }, PRNE_IPV_6 }, 853 },
- { { { PRNE_RESOLV_NS_IPV6_CLOUDFLARE_A }, PRNE_IPV_6 }, 853 },
- { { { PRNE_RESOLV_NS_IPV6_CLOUDFLARE_B }, PRNE_IPV_6 }, 853 },
- { { { PRNE_RESOLV_NS_IPV6_QUAD9_A }, PRNE_IPV_6 }, 853 },
- { { { PRNE_RESOLV_NS_IPV6_QUAD9_B }, PRNE_IPV_6 }, 853 },
- { { { PRNE_RESOLV_NS_IPV6_CLEANBROWSING_A }, PRNE_IPV_6 }, 853 },
- { { { PRNE_RESOLV_NS_IPV6_CLEANBROWSING_B }, PRNE_IPV_6 }, 853 }
+ { { { PRNE_RESOLV_NS_IPV6_GOOGLE_A }, PRNE_IPV_6, 0 }, 853 },
+ { { { PRNE_RESOLV_NS_IPV6_GOOGLE_B }, PRNE_IPV_6, 0 }, 853 },
+ { { { PRNE_RESOLV_NS_IPV6_CLOUDFLARE_A }, PRNE_IPV_6, 0 }, 853 },
+ { { { PRNE_RESOLV_NS_IPV6_CLOUDFLARE_B }, PRNE_IPV_6, 0 }, 853 },
+ { { { PRNE_RESOLV_NS_IPV6_QUAD9_A }, PRNE_IPV_6, 0 }, 853 },
+ { { { PRNE_RESOLV_NS_IPV6_QUAD9_B }, PRNE_IPV_6, 0 }, 853 },
+ { { { PRNE_RESOLV_NS_IPV6_CLEANBROWSING_A }, PRNE_IPV_6, 0 }, 853 },
+ { { { PRNE_RESOLV_NS_IPV6_CLEANBROWSING_B }, PRNE_IPV_6, 0 }, 853 }
};
const prne_resolv_ns_pool_t PRNE_RESOLV_DEF_IPV6_POOL = {