|
|
|
@ -13,14 +13,15 @@ |
|
|
|
#include "route_ping.h" |
|
|
|
#include "route_ping.h" |
|
|
|
#include "topo_node.h" |
|
|
|
#include "topo_node.h" |
|
|
|
#include "topo_group.h" |
|
|
|
#include "topo_group.h" |
|
|
|
|
|
|
|
#include "etcp_router.h" |
|
|
|
|
|
|
|
#include "route_crypto.h" |
|
|
|
#include "stcp_client.h" |
|
|
|
#include "stcp_client.h" |
|
|
|
#include "stun_nat.h" |
|
|
|
#include "stun_nat.h" |
|
|
|
#include "../lib/debug_config.h" |
|
|
|
#include "../lib/debug_config.h" |
|
|
|
#include "../lib/mem.h" |
|
|
|
#include "../lib/mem.h" |
|
|
|
#include "../lib/u_async.h" |
|
|
|
#include "../lib/u_async.h" |
|
|
|
|
|
|
|
|
|
|
|
#define NAT_WIRE_VERSION 2 |
|
|
|
#define NAT_WIRE_VERSION 3 |
|
|
|
#define NAT_MAX_HELPERS 32 |
|
|
|
|
|
|
|
#define NAT_MAX_BINDINGS 128 |
|
|
|
#define NAT_MAX_BINDINGS 128 |
|
|
|
#define NAT_MAX_PROBES 64 |
|
|
|
#define NAT_MAX_PROBES 64 |
|
|
|
#define NAT_MAX_CONTACTS 256 |
|
|
|
#define NAT_MAX_CONTACTS 256 |
|
|
|
@ -31,20 +32,21 @@ |
|
|
|
#define NAT_PROBE_COUNT 3 |
|
|
|
#define NAT_PROBE_COUNT 3 |
|
|
|
#define NAT_QUERY_TAG_SIZE (ROUTE_OBSERVE_TAG_SIZE + 9) |
|
|
|
#define NAT_QUERY_TAG_SIZE (ROUTE_OBSERVE_TAG_SIZE + 9) |
|
|
|
|
|
|
|
|
|
|
|
enum nat_command { NAT_FIND = 1, NAT_OFFER, NAT_RUN, NAT_RESULT }; |
|
|
|
enum nat_command { NAT_RUN = 1, NAT_RESULT }; |
|
|
|
enum nat_phase { NAT_IDLE, NAT_OBSERVE_B, NAT_FIND_C, NAT_PRE, NAT_OBSERVE_C, NAT_OBSERVE_ALT, NAT_POST, NAT_REPEAT_B, NAT_TCP }; |
|
|
|
enum nat_phase { NAT_IDLE, NAT_OBSERVE_B, NAT_PREPARE_C, NAT_PRE, NAT_OBSERVE_C, NAT_PREPARE_ALT, |
|
|
|
enum nat_step { NAT_STEP_PRE = 1, NAT_STEP_POST, NAT_STEP_TCP }; |
|
|
|
NAT_OBSERVE_ALT, NAT_POST, NAT_REPEAT_B, NAT_TCP }; |
|
|
|
|
|
|
|
enum nat_step { NAT_STEP_PREPARE = 1, NAT_STEP_PRE, NAT_STEP_ALT, NAT_STEP_POST, NAT_STEP_TCP }; |
|
|
|
|
|
|
|
|
|
|
|
/* Только байты: формат независим от alignment/endian платформы. */ |
|
|
|
/* Только байты: формат независим от alignment/endian платформы. */ |
|
|
|
struct nat_wire { |
|
|
|
struct nat_wire { |
|
|
|
uint8_t cmd, command, version, owner_socket, helper_socket, step, reason, excluded_count; |
|
|
|
uint8_t cmd, command, version, owner_socket, helper_socket, step, reason, sent, received, errors; |
|
|
|
uint8_t owner[8], generation[8], round[8], token[8], helper[8], timeout_ms[2]; |
|
|
|
uint8_t owner[8], generation[8], round[8], token[8], observer[8], helper[8], timeout_ms[2]; |
|
|
|
uint8_t target[ROUTE_ADDR_WIRE_SIZE], primary[ROUTE_ADDR_WIRE_SIZE], secondary[ROUTE_ADDR_WIRE_SIZE]; |
|
|
|
uint8_t target[ROUTE_ADDR_WIRE_SIZE], primary[ROUTE_ADDR_WIRE_SIZE], secondary[ROUTE_ADDR_WIRE_SIZE]; |
|
|
|
uint8_t owner_key[SC_PUBKEY_SIZE], helper_key[SC_PUBKEY_SIZE]; |
|
|
|
uint8_t observer_address[ROUTE_ADDR_WIRE_SIZE]; |
|
|
|
uint8_t excluded[NAT_MAX_HELPERS][8]; |
|
|
|
|
|
|
|
uint8_t sent, received, errors; |
|
|
|
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct nat_pair { uint64_t group, observer, helper; }; |
|
|
|
|
|
|
|
|
|
|
|
struct nat_socket { |
|
|
|
struct nat_socket { |
|
|
|
struct nat_socket *next; |
|
|
|
struct nat_socket *next; |
|
|
|
struct NAT_DETECTION *detector; |
|
|
|
struct NAT_DETECTION *detector; |
|
|
|
@ -56,22 +58,18 @@ struct nat_socket { |
|
|
|
uint64_t select_due; |
|
|
|
uint64_t select_due; |
|
|
|
uint8_t fallback_allowed; |
|
|
|
uint8_t fallback_allowed; |
|
|
|
uint8_t observer_key[32], helper_key[32]; |
|
|
|
uint8_t observer_key[32], helper_key[32]; |
|
|
|
uint64_t round, observer, helper, token, deadline, due, completed_tb, preferred_observer; |
|
|
|
uint64_t group_id, round, observer, helper, token, deadline, due, completed_tb, preferred_observer; |
|
|
|
uint64_t excluded[NAT_MAX_HELPERS]; |
|
|
|
struct nat_pair cursor, fallback; |
|
|
|
uint8_t contacts[NAT_MAX_CONTACTS][17]; |
|
|
|
uint8_t contacts[NAT_MAX_CONTACTS][17]; |
|
|
|
unsigned contact_count, excluded_count, phase, reason, retries; |
|
|
|
unsigned contact_count, phase, reason, retries; |
|
|
|
uint8_t history_loaded, history_complete, history_incomplete, filter_clean, pre_received, post_received, pre_healthy; |
|
|
|
uint8_t history_loaded, history_complete, history_incomplete, filter_clean, pre_received, post_received, pre_healthy; |
|
|
|
uint8_t helper_socket, active_ping, forced; |
|
|
|
uint8_t helper_socket, active_ping, forced, cycling, using_fallback; |
|
|
|
uint32_t rounds, helper_reselections; |
|
|
|
uint32_t rounds, helper_reselections; |
|
|
|
/* Уже контактировавший помощник годится для mapping после исчерпания свежих. */ |
|
|
|
|
|
|
|
uint64_t fallback_helper; |
|
|
|
|
|
|
|
uint8_t fallback_key[32], fallback_socket; |
|
|
|
|
|
|
|
struct sockaddr_storage fallback_address; |
|
|
|
|
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
struct nat_binding { |
|
|
|
struct nat_binding { |
|
|
|
struct nat_binding *next; |
|
|
|
struct nat_binding *next; |
|
|
|
uint64_t owner, generation, round, expires; |
|
|
|
uint64_t group_id, owner, generation, round, expires, helper, token; |
|
|
|
uint8_t owner_socket, owner_key[32]; |
|
|
|
uint8_t owner_socket, owner_key[32]; |
|
|
|
struct sockaddr_storage target; |
|
|
|
struct sockaddr_storage target; |
|
|
|
}; |
|
|
|
}; |
|
|
|
@ -80,8 +78,9 @@ struct nat_probe { |
|
|
|
struct nat_probe *next; |
|
|
|
struct nat_probe *next; |
|
|
|
struct NAT_DETECTION *detector; |
|
|
|
struct NAT_DETECTION *detector; |
|
|
|
struct nat_wire message; |
|
|
|
struct nat_wire message; |
|
|
|
uint64_t reply, source_generation, due, expires; |
|
|
|
uint64_t group_id, reply, source_generation, io_generation, due, expires; |
|
|
|
uint8_t source_socket, active, cancelled; |
|
|
|
uint8_t owner_key[32], observer_key[32]; |
|
|
|
|
|
|
|
uint8_t source_socket, io_socket, active, cancelled, alternate_fallback; |
|
|
|
struct stcp_client *tcp; |
|
|
|
struct stcp_client *tcp; |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
@ -91,6 +90,7 @@ struct NAT_DETECTION { |
|
|
|
struct nat_binding *bindings; |
|
|
|
struct nat_binding *bindings; |
|
|
|
struct nat_probe *probes; |
|
|
|
struct nat_probe *probes; |
|
|
|
void *timer; |
|
|
|
void *timer; |
|
|
|
|
|
|
|
void *topology_wake; |
|
|
|
uint64_t publish_after; |
|
|
|
uint64_t publish_after; |
|
|
|
uint8_t allow_local, stopping, history_table_ready, automatic, publish_pending; |
|
|
|
uint8_t allow_local, stopping, history_table_ready, automatic, publish_pending; |
|
|
|
}; |
|
|
|
}; |
|
|
|
@ -102,6 +102,8 @@ static int owner_observe(struct nat_socket *); |
|
|
|
static int owner_run(struct nat_socket *, uint8_t); |
|
|
|
static int owner_run(struct nat_socket *, uint8_t); |
|
|
|
static void owner_finish(struct nat_socket *, uint8_t); |
|
|
|
static void owner_finish(struct nat_socket *, uint8_t); |
|
|
|
static void helper_remove(struct nat_probe *); |
|
|
|
static void helper_remove(struct nat_probe *); |
|
|
|
|
|
|
|
static int helper_send(struct nat_probe *); |
|
|
|
|
|
|
|
static void owner_start(struct nat_socket *); |
|
|
|
|
|
|
|
|
|
|
|
static uint64_t read64(const uint8_t *data) { |
|
|
|
static uint64_t read64(const uint8_t *data) { |
|
|
|
uint64_t value = 0; |
|
|
|
uint64_t value = 0; |
|
|
|
@ -126,12 +128,6 @@ const char *nat_check_reason_name(uint8_t reason) { |
|
|
|
return reason < sizeof(names) / sizeof(names[0]) ? names[reason] : "invalid_reason"; |
|
|
|
return reason < sizeof(names) / sizeof(names[0]) ? names[reason] : "invalid_reason"; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct ETCP_CONN *live_connection(struct NAT_DETECTION *detector, uint64_t node) { |
|
|
|
|
|
|
|
struct ETCP_CONN *connection = instance_find_conn(detector->instance, node); |
|
|
|
|
|
|
|
return connection && connection->state != 2 && !connection->close_requested && connection->links_up && |
|
|
|
|
|
|
|
connection->crypto_ctx.peer_key_set ? connection : NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct ETCP_SOCKET *find_socket(struct NAT_DETECTION *detector, uint8_t id, uint64_t generation) { |
|
|
|
static struct ETCP_SOCKET *find_socket(struct NAT_DETECTION *detector, uint8_t id, uint64_t generation) { |
|
|
|
for (struct ETCP_SOCKET *socket = detector->instance->etcp_sockets; socket; socket = socket->next) |
|
|
|
for (struct ETCP_SOCKET *socket = detector->instance->etcp_sockets; socket; socket = socket->next) |
|
|
|
if (socket->sock_id == id && (!generation || socket->generation == generation)) return socket; |
|
|
|
if (socket->sock_id == id && (!generation || socket->generation == generation)) return socket; |
|
|
|
@ -150,6 +146,119 @@ static int public_address(struct NAT_DETECTION *detector, const struct sockaddr_ |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Подписанная идентичность участника выбранной группы; сохранённый bootstrap не разрешает управление. */ |
|
|
|
|
|
|
|
static const struct TOPO_NODE *group_node(struct NAT_DETECTION *detector, uint64_t group_id, uint64_t node_id) { |
|
|
|
|
|
|
|
struct TOPO_GROUP *group = topo_groups_find(detector->instance->topo_groups, group_id); |
|
|
|
|
|
|
|
if (!group || group->stopping || (node_id != detector->instance->node_id && !topo_node_find_by_id(group, node_id))) return NULL; |
|
|
|
|
|
|
|
const struct TOPO_NODE *node = topo_node_registry_find(detector->instance->topo_groups, node_id); |
|
|
|
|
|
|
|
return node && node->timestamp ? node : NULL; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Управление допускает транзит и TCP, но следующий хоп должен завершить согласование этой группы. */ |
|
|
|
|
|
|
|
static int control_route(struct NAT_DETECTION *detector, uint64_t group_id, uint64_t node_id) { |
|
|
|
|
|
|
|
if (!group_node(detector, group_id, node_id)) return 0; |
|
|
|
|
|
|
|
struct ETCP_ROUTER_PATH path = etcp_router_get_path(detector->instance, group_id, node_id, ETCP_RT_ID_NAT_DETECTION); |
|
|
|
|
|
|
|
struct TOPO_GROUP *group = topo_groups_find(detector->instance->topo_groups, group_id); |
|
|
|
|
|
|
|
return path.type != CONN_TYPE_NONE && topo_group_peer_ready(group, path.next_hop_node_id); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Выбирает сокет по NODEINFO. Помощнику разрешён приватный endpoint: его mapping измеряется перед ingress. */ |
|
|
|
|
|
|
|
static int node_udp_endpoint(struct NAT_DETECTION *detector, const struct TOPO_NODE *node, int family, int allow_private, |
|
|
|
|
|
|
|
struct sockaddr_storage *address, uint8_t *socket_id) { |
|
|
|
|
|
|
|
int best = 4; |
|
|
|
|
|
|
|
for (const struct TOPO_ADDR4 *a = family == AF_INET ? node->v4_addrs : NULL; a; a = a->next) { |
|
|
|
|
|
|
|
if (!(a->protocol & TOPO_PROTO_UDP) || !a->port) continue; |
|
|
|
|
|
|
|
const struct TOPO_SOCKMETA4 *meta = node->v4_sock_meta; |
|
|
|
|
|
|
|
while (meta && meta->id != a->socket_id) meta = meta->next; |
|
|
|
|
|
|
|
if (meta && (meta->config_type == CFG_SERVER_TYPE_PRIVATE || meta->config_type == CFG_SERVER_TYPE_LOCAL)) continue; |
|
|
|
|
|
|
|
struct sockaddr_storage candidate = {0}; struct sockaddr_in *v4 = (struct sockaddr_in *)&candidate; |
|
|
|
|
|
|
|
v4->sin_family = AF_INET; memcpy(&v4->sin_addr, a->addr, 4); v4->sin_port = htons(a->port); |
|
|
|
|
|
|
|
int rank = public_address(detector, &candidate) ? 0 : 2; |
|
|
|
|
|
|
|
if ((!allow_private && rank) || rank > best || (rank == best && a->socket_id >= *socket_id)) continue; |
|
|
|
|
|
|
|
best = rank; *address = candidate; *socket_id = a->socket_id; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
for (const struct TOPO_ADDR6 *a = family == AF_INET6 ? node->v6_addrs : NULL; a; a = a->next) { |
|
|
|
|
|
|
|
if (!(a->protocol & TOPO_PROTO_UDP) || !a->port) continue; |
|
|
|
|
|
|
|
const struct TOPO_SOCKMETA6 *meta = node->v6_sock_meta; |
|
|
|
|
|
|
|
while (meta && meta->id != a->socket_id) meta = meta->next; |
|
|
|
|
|
|
|
if (meta && (meta->config_type == CFG_SERVER_TYPE_PRIVATE || meta->config_type == CFG_SERVER_TYPE_LOCAL)) continue; |
|
|
|
|
|
|
|
struct sockaddr_storage candidate = {0}; struct sockaddr_in6 *v6 = (struct sockaddr_in6 *)&candidate; |
|
|
|
|
|
|
|
v6->sin6_family = AF_INET6; memcpy(&v6->sin6_addr, a->addr, 16); v6->sin6_port = htons(a->port); |
|
|
|
|
|
|
|
int rank = public_address(detector, &candidate) ? 0 : 2; |
|
|
|
|
|
|
|
if ((!allow_private && rank) || rank > best || (rank == best && a->socket_id >= *socket_id)) continue; |
|
|
|
|
|
|
|
best = rank; *address = candidate; *socket_id = a->socket_id; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* Наблюдаемый адрес уже работающего UDP помогает bootstrap за NAT; прямой линк не является условием отбора. */ |
|
|
|
|
|
|
|
struct ETCP_CONN *connection = instance_find_conn(detector->instance, node->node_id); |
|
|
|
|
|
|
|
for (struct ETCP_LINK *link = connection ? connection->links : NULL; link; link = link->next) { |
|
|
|
|
|
|
|
if (link->is_tcp || !link->initialized || !link->link_status || link->remote_only_local || |
|
|
|
|
|
|
|
link->remote_addr.ss_family != family || !public_address(detector, &link->remote_addr)) continue; |
|
|
|
|
|
|
|
if (best == 0) break; |
|
|
|
|
|
|
|
*address = link->remote_addr; *socket_id = link->remote_socket_id; best = 1; break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return best < 4; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int pair_after(struct nat_pair a, struct nat_pair b) { |
|
|
|
|
|
|
|
if (a.group != b.group) return a.group > b.group; |
|
|
|
|
|
|
|
if (a.observer != b.observer) return a.observer > b.observer; |
|
|
|
|
|
|
|
return a.helper > b.helper; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Обходит пары всех групп без ограничения числа узлов и без хранения указателей на топологию. */ |
|
|
|
|
|
|
|
static int select_pair(struct nat_socket *state) { |
|
|
|
|
|
|
|
struct NAT_DETECTION *detector = state->detector; |
|
|
|
|
|
|
|
struct nat_pair best = {0}; |
|
|
|
|
|
|
|
struct sockaddr_storage observer_address = {0}, helper_address = {0}; |
|
|
|
|
|
|
|
uint8_t observer_key[32] = {0}, helper_key[32] = {0}, helper_socket = 0; |
|
|
|
|
|
|
|
unsigned observers = 0, groups = 0; |
|
|
|
|
|
|
|
for (struct ll_entry *e = detector->instance->topo_groups->group_list->head; e; e = e->next) { |
|
|
|
|
|
|
|
struct TOPO_GROUP *group = (struct TOPO_GROUP *)e; |
|
|
|
|
|
|
|
if (group->stopping || !group->local_node) continue; |
|
|
|
|
|
|
|
groups++; |
|
|
|
|
|
|
|
for (struct ll_entry *b = group->nodes->head; b; b = b->next) { |
|
|
|
|
|
|
|
uint64_t observer = ((struct TOPO_GROUP_NODE *)b)->node_id; |
|
|
|
|
|
|
|
if (observer == detector->instance->node_id || (state->preferred_observer && observer != state->preferred_observer) || |
|
|
|
|
|
|
|
!control_route(detector, group->group_id, observer)) continue; |
|
|
|
|
|
|
|
const struct TOPO_NODE *bn = group_node(detector, group->group_id, observer); |
|
|
|
|
|
|
|
struct sockaddr_storage ba = {0}; uint8_t bs = 0; |
|
|
|
|
|
|
|
if (!state->socket->is_tcp && !node_udp_endpoint(detector, bn, state->local.ss_family, 0, &ba, &bs)) continue; |
|
|
|
|
|
|
|
observers++; |
|
|
|
|
|
|
|
for (struct ll_entry *c = state->socket->is_tcp ? b : group->nodes->head; c; c = state->socket->is_tcp ? NULL : c->next) { |
|
|
|
|
|
|
|
uint64_t helper = ((struct TOPO_GROUP_NODE *)c)->node_id; |
|
|
|
|
|
|
|
if (helper == detector->instance->node_id || (!state->socket->is_tcp && helper == observer) || |
|
|
|
|
|
|
|
!control_route(detector, group->group_id, helper)) continue; |
|
|
|
|
|
|
|
const struct TOPO_NODE *cn = group_node(detector, group->group_id, helper); |
|
|
|
|
|
|
|
struct sockaddr_storage ca = {0}; uint8_t cs = 0; |
|
|
|
|
|
|
|
if (!state->socket->is_tcp && !node_udp_endpoint(detector, cn, state->local.ss_family, 1, &ca, &cs)) continue; |
|
|
|
|
|
|
|
struct nat_pair candidate = {group->group_id, observer, helper}; |
|
|
|
|
|
|
|
if (state->using_fallback) { |
|
|
|
|
|
|
|
if (memcmp(&candidate, &state->fallback, sizeof(candidate))) continue; |
|
|
|
|
|
|
|
} else if (!pair_after(candidate, state->cursor)) continue; |
|
|
|
|
|
|
|
if (best.group && !pair_after(best, candidate)) continue; |
|
|
|
|
|
|
|
best = candidate; observer_address = ba; helper_address = ca; helper_socket = cs; |
|
|
|
|
|
|
|
memcpy(observer_key, bn->public_key, 32); memcpy(helper_key, cn->public_key, 32); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!best.group) { |
|
|
|
|
|
|
|
if (!state->using_fallback && state->fallback.group) { state->using_fallback = 1; return select_pair(state); } |
|
|
|
|
|
|
|
state->reason = observers ? NAT_REASON_NO_HELPER : NAT_REASON_NO_OBSERVER; |
|
|
|
|
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT candidate cycle exhausted socket=%s groups=%u observers=%u reason=%s", |
|
|
|
|
|
|
|
state->socket->name, groups, observers, nat_check_reason_name(state->reason)); |
|
|
|
|
|
|
|
return -1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!state->using_fallback) state->cursor = best; |
|
|
|
|
|
|
|
state->group_id = best.group; state->observer = best.observer; state->helper = best.helper; |
|
|
|
|
|
|
|
state->observer_address = observer_address; state->helper_address = helper_address; state->helper_socket = helper_socket; |
|
|
|
|
|
|
|
memcpy(state->observer_key, observer_key, 32); memcpy(state->helper_key, helper_key, 32); |
|
|
|
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_NAT, "NAT candidates socket=%s group=%016llx observer=%016llx endpoint=%s helper=%016llx candidate=%s fallback=%u", |
|
|
|
|
|
|
|
state->socket->name, (unsigned long long)best.group, (unsigned long long)best.observer, |
|
|
|
|
|
|
|
sockaddr_storage_to_str(&observer_address).str, (unsigned long long)best.helper, |
|
|
|
|
|
|
|
sockaddr_storage_to_str(&helper_address).str, state->using_fallback); |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void publish(struct NAT_DETECTION *detector) { |
|
|
|
static void publish(struct NAT_DETECTION *detector) { |
|
|
|
if (detector->stopping || !detector->instance->topo_groups) return; |
|
|
|
if (detector->stopping || !detector->instance->topo_groups) return; |
|
|
|
detector->publish_pending = topo_node_update_my_addresses(detector->instance) < 0; |
|
|
|
detector->publish_pending = topo_node_update_my_addresses(detector->instance) < 0; |
|
|
|
@ -279,52 +388,52 @@ void nat_detection_note_send(struct NAT_DETECTION *detector, struct ETCP_SOCKET |
|
|
|
if (history_insert(state, remote)) history_mark_incomplete(state); |
|
|
|
if (history_insert(state, remote)) history_mark_incomplete(state); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int send_control(struct NAT_DETECTION *detector, uint64_t destination, struct nat_wire *message) { |
|
|
|
static int send_control(struct NAT_DETECTION *detector, uint64_t group_id, uint64_t destination, struct nat_wire *message) { |
|
|
|
struct ETCP_CONN *connection = live_connection(detector, destination); |
|
|
|
if (!control_route(detector, group_id, destination)) { |
|
|
|
if (!connection) { |
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT control route unavailable group=%016llx peer=%016llx", |
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT control peer unavailable peer=%016llx", (unsigned long long)destination); return -1; |
|
|
|
(unsigned long long)group_id, (unsigned long long)destination); return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
struct ll_entry *entry = queue_entry_new(0); |
|
|
|
struct ll_entry *entry = queue_entry_new(0); |
|
|
|
if (!entry) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT control queue allocation failed"); return -1; } |
|
|
|
if (!entry) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT control queue allocation failed"); return -1; } |
|
|
|
entry->dgram = u_malloc(sizeof(*message)); |
|
|
|
entry->dgram = u_malloc(1 + sizeof(*message)); |
|
|
|
if (!entry->dgram) { queue_entry_free(entry); DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT control allocation failed"); return -1; } |
|
|
|
if (!entry->dgram) { queue_entry_free(entry); DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT control allocation failed"); return -1; } |
|
|
|
message->cmd = ETCP_ID_NAT_DETECTION; message->version = NAT_WIRE_VERSION; |
|
|
|
message->cmd = ETCP_RT_ID_NAT_DETECTION; message->version = NAT_WIRE_VERSION; |
|
|
|
memcpy(entry->dgram, message, sizeof(*message)); entry->len = sizeof(*message); |
|
|
|
entry->dgram[0] = ETCP_RT_ID_NAT_DETECTION; |
|
|
|
if (etcp_send(connection, entry)) { |
|
|
|
memcpy(entry->dgram + 1, message, sizeof(*message)); entry->len = 1 + sizeof(*message); |
|
|
|
queue_dgram_free(entry); queue_entry_free(entry); |
|
|
|
if (etcp_route_send(detector->instance, group_id, destination, entry, 0, ROUTE_CRYPTO_SIGN | ROUTE_CRYPTO_ENCRYPT)) { |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT control send failed peer=%016llx command=%u", |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT control send failed group=%016llx peer=%016llx command=%u", |
|
|
|
(unsigned long long)destination, message->command); return -1; |
|
|
|
(unsigned long long)group_id, (unsigned long long)destination, message->command); return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT control TX command=%u step=%u peer=%016llx owner=%016llx round=%016llx helper=%016llx", |
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT control TX group=%016llx command=%u step=%u peer=%016llx owner=%016llx round=%016llx helper=%016llx", |
|
|
|
message->command, message->step, (unsigned long long)destination, |
|
|
|
(unsigned long long)group_id, message->command, message->step, (unsigned long long)destination, |
|
|
|
(unsigned long long)read64(message->owner), (unsigned long long)read64(message->round), |
|
|
|
(unsigned long long)read64(message->owner), (unsigned long long)read64(message->round), |
|
|
|
(unsigned long long)read64(message->helper)); |
|
|
|
(unsigned long long)read64(message->helper)); |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void make_message(struct nat_socket *state, struct nat_wire *message, uint8_t command) { |
|
|
|
static int make_message(struct nat_socket *state, struct nat_wire *message, uint8_t command) { |
|
|
|
memset(message, 0, sizeof(*message)); message->command = command; |
|
|
|
memset(message, 0, sizeof(*message)); message->command = command; |
|
|
|
message->owner_socket = state->socket->sock_id; message->helper_socket = state->helper_socket; |
|
|
|
message->owner_socket = state->socket->sock_id; message->helper_socket = state->helper_socket; |
|
|
|
write64(message->owner, state->detector->instance->node_id); |
|
|
|
write64(message->owner, state->detector->instance->node_id); |
|
|
|
write64(message->generation, state->socket->generation); write64(message->round, state->round); |
|
|
|
write64(message->generation, state->socket->generation); write64(message->round, state->round); |
|
|
|
write64(message->helper, state->helper); write64(message->token, state->token); |
|
|
|
write64(message->helper, state->helper); write64(message->observer, state->observer); write64(message->token, state->token); |
|
|
|
memcpy(message->owner_key, state->detector->instance->my_keys.public_key, 32); |
|
|
|
if (route_ping_addr_encode(message->target, state->socket->is_tcp ? &state->local : &state->baseline)) return -1; |
|
|
|
memcpy(message->helper_key, state->helper_key, 32); |
|
|
|
if (state->helper_address.ss_family && route_ping_addr_encode(message->primary, &state->helper_address)) return -1; |
|
|
|
route_ping_addr_encode(message->target, state->socket->is_tcp ? &state->local : &state->baseline); |
|
|
|
if (state->observer_address.ss_family && route_ping_addr_encode(message->observer_address, &state->observer_address)) return -1; |
|
|
|
if (state->helper_address.ss_family) route_ping_addr_encode(message->primary, &state->helper_address); |
|
|
|
|
|
|
|
int timeout = 1000; |
|
|
|
int timeout = 1000; |
|
|
|
struct ETCP_CONN *observer = live_connection(state->detector, state->observer); |
|
|
|
struct ETCP_CONN *observer = topo_group_find_conn_for_node( |
|
|
|
|
|
|
|
topo_groups_find(state->detector->instance->topo_groups, state->group_id), state->observer); |
|
|
|
for (struct ETCP_LINK *link = observer ? observer->links : NULL; link; link = link->next) |
|
|
|
for (struct ETCP_LINK *link = observer ? observer->links : NULL; link; link = link->next) |
|
|
|
if (link->rtt_last / 10 * 4 > timeout) timeout = link->rtt_last / 10 * 4; |
|
|
|
if (link->rtt_last / 10 * 4 > timeout) timeout = link->rtt_last / 10 * 4; |
|
|
|
if (timeout > 3000) timeout = 3000; |
|
|
|
if (timeout > 3000) timeout = 3000; |
|
|
|
message->timeout_ms[0] = timeout >> 8; message->timeout_ms[1] = timeout; |
|
|
|
message->timeout_ms[0] = timeout >> 8; message->timeout_ms[1] = timeout; |
|
|
|
message->excluded_count = state->excluded_count; |
|
|
|
return 0; |
|
|
|
for (unsigned i = 0; i < state->excluded_count; i++) write64(message->excluded[i], state->excluded[i]); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static struct nat_binding *binding_find(struct NAT_DETECTION *detector, uint64_t owner, uint64_t generation, uint64_t round) { |
|
|
|
static struct nat_binding *binding_find(struct NAT_DETECTION *detector, uint64_t group_id, uint64_t owner, |
|
|
|
|
|
|
|
uint64_t generation, uint64_t round) { |
|
|
|
for (struct nat_binding *binding = detector->bindings; binding; binding = binding->next) |
|
|
|
for (struct nat_binding *binding = detector->bindings; binding; binding = binding->next) |
|
|
|
if (binding->owner == owner && binding->generation == generation && binding->round == round && |
|
|
|
if (binding->group_id == group_id && binding->owner == owner && binding->generation == generation && binding->round == round && |
|
|
|
binding->expires > get_time_tb()) return binding; |
|
|
|
binding->expires > get_time_tb()) return binding; |
|
|
|
return NULL; |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -333,12 +442,17 @@ void nat_detection_record_observation(struct NAT_DETECTION *detector, struct ETC |
|
|
|
const uint8_t peer_key[32], const struct sockaddr_storage *source, |
|
|
|
const uint8_t peer_key[32], const struct sockaddr_storage *source, |
|
|
|
const uint8_t *tag, size_t length) { |
|
|
|
const uint8_t *tag, size_t length) { |
|
|
|
if (!detector || detector->stopping) return; |
|
|
|
if (!detector || detector->stopping) return; |
|
|
|
if (length != ROUTE_OBSERVE_TAG_SIZE || !tag || memcmp(tag, "NAT2UDP!", 8)) { |
|
|
|
if (!socket || socket->socks_udp || length != ROUTE_OBSERVE_TAG_SIZE || !tag || memcmp(tag, "NAT3UDP!", 8)) { |
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT observation query has invalid tag length=%zu", length); return; |
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT observation query has invalid tag length=%zu", length); return; |
|
|
|
} |
|
|
|
} |
|
|
|
uint64_t owner = sc_derive_node_id_from_pubkey(peer_key), generation = read64(tag + 9), round = read64(tag + 17); |
|
|
|
uint64_t owner = sc_derive_node_id_from_pubkey(peer_key), generation = read64(tag + 9), round = read64(tag + 17); |
|
|
|
if (!generation || !round) { DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT observation query has zero generation/round"); return; } |
|
|
|
uint64_t group_id = read64(tag + 25); |
|
|
|
struct nat_binding *binding = binding_find(detector, owner, generation, round); |
|
|
|
const struct TOPO_NODE *node = group_node(detector, group_id, owner); |
|
|
|
|
|
|
|
if (!generation || !round || !node || memcmp(node->public_key, peer_key, 32)) { |
|
|
|
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT observation has invalid group/identity group=%016llx owner=%016llx", |
|
|
|
|
|
|
|
(unsigned long long)group_id, (unsigned long long)owner); return; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
struct nat_binding *binding = binding_find(detector, group_id, owner, generation, round); |
|
|
|
if (!binding) { |
|
|
|
if (!binding) { |
|
|
|
unsigned count = 0; |
|
|
|
unsigned count = 0; |
|
|
|
for (struct nat_binding *item = detector->bindings; item; item = item->next) count++; |
|
|
|
for (struct nat_binding *item = detector->bindings; item; item = item->next) count++; |
|
|
|
@ -347,10 +461,11 @@ void nat_detection_record_observation(struct NAT_DETECTION *detector, struct ETC |
|
|
|
if (!binding) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT observation cache allocation failed"); return; } |
|
|
|
if (!binding) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT observation cache allocation failed"); return; } |
|
|
|
binding->next = detector->bindings; detector->bindings = binding; |
|
|
|
binding->next = detector->bindings; detector->bindings = binding; |
|
|
|
} |
|
|
|
} |
|
|
|
binding->owner = owner; binding->generation = generation; binding->round = round; binding->owner_socket = tag[8]; |
|
|
|
binding->group_id = group_id; binding->owner = owner; binding->generation = generation; |
|
|
|
|
|
|
|
binding->round = round; binding->owner_socket = tag[8]; |
|
|
|
memcpy(binding->owner_key, peer_key, 32); binding->target = *source; binding->expires = get_time_tb() + NAT_ROUND_TB; |
|
|
|
memcpy(binding->owner_key, peer_key, 32); binding->target = *source; binding->expires = get_time_tb() + NAT_ROUND_TB; |
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT observation owner=%016llx socket=%u generation=%016llx round=%016llx observed=%s via=%s", |
|
|
|
DEBUG_DEBUG(DEBUG_CATEGORY_NAT, "NAT observation group=%016llx owner=%016llx socket=%u generation=%016llx round=%016llx observed=%s via=%s", |
|
|
|
(unsigned long long)owner, tag[8], (unsigned long long)generation, (unsigned long long)round, |
|
|
|
(unsigned long long)group_id, (unsigned long long)owner, tag[8], (unsigned long long)generation, (unsigned long long)round, |
|
|
|
sockaddr_storage_to_str(source).str, socket->name); |
|
|
|
sockaddr_storage_to_str(source).str, socket->name); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|