Browse Source

Select NAT candidates across groups and route authenticated control

master
evgeny 7 days ago
parent
commit
77ca1ec3dd
  1. 231
      src/routing_layer/nat_detection.c
  2. 8
      src/routing_layer/nat_detection.h

231
src/routing_layer/nat_detection.c

@ -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);
} }

8
src/routing_layer/nat_detection.h

@ -1,5 +1,5 @@
/* Владелец измеряет собственный endpoint. Пиры передают наблюдения и выполняют /* Владелец измеряет собственный endpoint. Пиры передают наблюдения и выполняют
* прямые пробы; управление проверяющим идёт через явно выбранного посредника. * прямые пробы; управление идёт через маршруты одной из доступных групп.
* Все операции и callbacks выполняются в uasync-потоке ядра. */ * Все операции и callbacks выполняются в uasync-потоке ядра. */
#ifndef NAT_DETECTION_H #ifndef NAT_DETECTION_H
#define NAT_DETECTION_H #define NAT_DETECTION_H
@ -28,7 +28,7 @@ enum nat_check_reason {
struct nat_check_status { struct nat_check_status {
struct address_profile measured_profile, effective_profile; struct address_profile measured_profile, effective_profile;
uint64_t generation, round; uint64_t generation, round;
uint64_t observer, helper; uint64_t group_id, observer, helper;
uint32_t rounds, helper_reselections; uint32_t rounds, helper_reselections;
uint8_t phase, reason, history_complete; uint8_t phase, reason, history_complete;
uint8_t fallback_allowed; uint8_t fallback_allowed;
@ -36,6 +36,10 @@ struct nat_check_status {
struct NAT_DETECTION *nat_detection_create(struct UTUN_INSTANCE *instance); struct NAT_DETECTION *nat_detection_create(struct UTUN_INSTANCE *instance);
void nat_detection_destroy(struct NAT_DETECTION *detector); void nat_detection_destroy(struct NAT_DETECTION *detector);
/* Объединить изменения NODEINFO/READY и пересмотреть доступные группы в следующем uasync-вызове. */
void nat_detection_topology_changed(struct NAT_DETECTION *detector);
/* Отменить раунды, задачи помощников и наблюдения до закрытия router-каналов группы. */
void nat_detection_cancel_group(struct NAT_DETECTION *detector, uint64_t group_id);
void nat_detection_link_ready(struct NAT_DETECTION *detector, struct ETCP_LINK *link); void nat_detection_link_ready(struct NAT_DETECTION *detector, struct ETCP_LINK *link);
void nat_detection_cancel_for_conn(struct NAT_DETECTION *detector, struct ETCP_CONN *connection); void nat_detection_cancel_for_conn(struct NAT_DETECTION *detector, struct ETCP_CONN *connection);
void nat_detection_socket_removed(struct NAT_DETECTION *detector, struct ETCP_SOCKET *socket); void nat_detection_socket_removed(struct NAT_DETECTION *detector, struct ETCP_SOCKET *socket);

Loading…
Cancel
Save