|
|
|
|
@ -17,6 +17,7 @@
|
|
|
|
|
#include "route_crypto.h" |
|
|
|
|
#include "stcp_client.h" |
|
|
|
|
#include "stun_nat.h" |
|
|
|
|
#include "sock_match.h" |
|
|
|
|
#include "../lib/debug_config.h" |
|
|
|
|
#include "../lib/mem.h" |
|
|
|
|
#include "../lib/u_async.h" |
|
|
|
|
@ -29,10 +30,11 @@
|
|
|
|
|
#define NAT_ROUND_TB 300000 |
|
|
|
|
#define NAT_REFRESH_TB 18000000 |
|
|
|
|
#define NAT_RETRY_TB 300000 |
|
|
|
|
#define NAT_FAILURE_RECHECK_TB 3000000 |
|
|
|
|
#define NAT_PROBE_COUNT 3 |
|
|
|
|
#define NAT_QUERY_TAG_SIZE (ROUTE_OBSERVE_TAG_SIZE + 9) |
|
|
|
|
|
|
|
|
|
enum nat_command { NAT_RUN = 1, NAT_RESULT }; |
|
|
|
|
enum nat_command { NAT_RUN = 1, NAT_RESULT, NAT_RECHECK }; |
|
|
|
|
enum nat_phase { NAT_IDLE, NAT_OBSERVE_B, NAT_PREPARE_C, NAT_PRE, NAT_OBSERVE_C, NAT_PREPARE_ALT, |
|
|
|
|
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 }; |
|
|
|
|
@ -46,6 +48,7 @@ struct nat_wire {
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
struct nat_pair { uint64_t group, observer, helper; }; |
|
|
|
|
struct nat_recheck_wire { uint8_t cmd, command, version, socket_id, address[ROUTE_ADDR_WIRE_SIZE]; }; |
|
|
|
|
|
|
|
|
|
struct nat_socket { |
|
|
|
|
struct nat_socket *next; |
|
|
|
|
@ -55,7 +58,7 @@ struct nat_socket {
|
|
|
|
|
struct sockaddr_storage baseline, helper_seen, alternate_seen; |
|
|
|
|
struct sockaddr_storage measured_address; |
|
|
|
|
struct address_profile measured_profile; |
|
|
|
|
uint64_t select_due, available_fingerprint, reservation_fingerprint, cold_until; |
|
|
|
|
uint64_t select_due, available_fingerprint, reservation_fingerprint, cold_until, failure_recheck_tb; |
|
|
|
|
uint8_t fallback_allowed; |
|
|
|
|
uint8_t observer_key[32], helper_key[32]; |
|
|
|
|
uint64_t group_id, round, observer, helper, token, deadline, due, completed_tb, preferred_observer; |
|
|
|
|
@ -106,6 +109,17 @@ static int helper_send(struct nat_probe *);
|
|
|
|
|
static void owner_start(struct nat_socket *); |
|
|
|
|
static int contacted(struct nat_socket *, const struct sockaddr_storage *); |
|
|
|
|
|
|
|
|
|
/* Не сбрасывает последний успех; повторные ошибки одного endpoint объединяются и ограничиваются по частоте. */ |
|
|
|
|
static int schedule_failure_recheck(struct nat_socket *state, uint64_t peer, int remote) { |
|
|
|
|
uint64_t now = get_time_tb(); |
|
|
|
|
if (!state || !state->detector->automatic || state->phase || state->cycling || state->forced || |
|
|
|
|
(state->failure_recheck_tb && now - state->failure_recheck_tb < NAT_FAILURE_RECHECK_TB)) return 0; |
|
|
|
|
state->failure_recheck_tb = now; state->due = now; state->forced = 1; state->preferred_observer = 0; |
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_NAT, "NAT failure recheck scheduled socket=%s generation=%016llx peer=%016llx remote_request=%d", |
|
|
|
|
state->socket->name, (unsigned long long)state->socket->generation, (unsigned long long)peer, remote); |
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static uint64_t read64(const uint8_t *data) { |
|
|
|
|
uint64_t value = 0; |
|
|
|
|
for (unsigned i = 0; i < 8; i++) value = (value << 8) | data[i]; |
|
|
|
|
@ -1029,13 +1043,29 @@ static void receive_control(struct ETCP_CONN *from, struct ll_entry *entry) {
|
|
|
|
|
(unsigned long long)group_id, (unsigned long long)sender); |
|
|
|
|
queue_dgram_free(entry); queue_entry_free(entry); cancel_route(detector, group_id, sender); return; |
|
|
|
|
} |
|
|
|
|
if (entry->len != ROUTER_SVC_HDR_SIZE + sizeof(struct nat_wire) || |
|
|
|
|
entry->dgram[ROUTER_SVC_FLAGS_OFF] != (ROUTER_FLAG_SIGNED | ROUTER_FLAG_ENCRYPTED) || |
|
|
|
|
if (entry->dgram[ROUTER_SVC_FLAGS_OFF] != (ROUTER_FLAG_SIGNED | ROUTER_FLAG_ENCRYPTED) || |
|
|
|
|
!group_node(detector, group_id, sender)) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT routed control rejected group=%016llx sender=%016llx size=%zu flags=%u", |
|
|
|
|
(unsigned long long)group_id, (unsigned long long)sender, entry->len, entry->dgram[ROUTER_SVC_FLAGS_OFF]); |
|
|
|
|
queue_dgram_free(entry); queue_entry_free(entry); return; |
|
|
|
|
} |
|
|
|
|
if (entry->len == ROUTER_SVC_HDR_SIZE + sizeof(struct nat_recheck_wire)) { |
|
|
|
|
struct nat_recheck_wire request; memcpy(&request, entry->dgram + ROUTER_SVC_PAYLOAD_OFF, sizeof(request)); |
|
|
|
|
queue_dgram_free(entry); queue_entry_free(entry); |
|
|
|
|
struct ETCP_SOCKET *socket = find_socket(detector, request.socket_id, 0); |
|
|
|
|
struct sockaddr_storage address = {0}; |
|
|
|
|
if (request.cmd != ETCP_RT_ID_NAT_DETECTION || request.command != NAT_RECHECK || request.version != NAT_WIRE_VERSION || |
|
|
|
|
!socket || socket->is_tcp || socket->probe_only || socket->socks_udp || route_ping_addr_decode(&address, request.address) || |
|
|
|
|
(!route_ping_addr_equal(&address, &socket->local_addr, 1) && !route_ping_addr_equal(&address, &socket->nat_addr, 1))) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT failure recheck rejected group=%016llx peer=%016llx socket=%u: stale/invalid endpoint", |
|
|
|
|
(unsigned long long)group_id, (unsigned long long)sender, request.socket_id); return; |
|
|
|
|
} |
|
|
|
|
schedule_failure_recheck(socket_state(detector, socket, 1), sender, 1); return; |
|
|
|
|
} |
|
|
|
|
if (entry->len != ROUTER_SVC_HDR_SIZE + sizeof(struct nat_wire)) { |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT control invalid payload size=%zu", entry->len - ROUTER_SVC_HDR_SIZE); |
|
|
|
|
queue_dgram_free(entry); queue_entry_free(entry); return; |
|
|
|
|
} |
|
|
|
|
struct nat_wire message; memcpy(&message, entry->dgram + ROUTER_SVC_PAYLOAD_OFF, sizeof(message)); |
|
|
|
|
queue_dgram_free(entry); queue_entry_free(entry); |
|
|
|
|
if (message.cmd != ETCP_RT_ID_NAT_DETECTION || message.version != NAT_WIRE_VERSION || |
|
|
|
|
@ -1290,6 +1320,57 @@ void nat_detection_cancel_for_conn(struct NAT_DETECTION *detector, struct ETCP_C
|
|
|
|
|
nat_detection_topology_changed(detector); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/* Сопоставление с текущим подписанным snapshot не зависит от remote_socket_id до завершения INIT. */ |
|
|
|
|
void nat_detection_connection_failed(struct NAT_DETECTION *detector, struct ETCP_CONN *connection, int reverse_done) { |
|
|
|
|
if (!detector || detector->stopping || !detector->automatic || !connection || connection->links_up) return; |
|
|
|
|
const struct TOPO_NODE *node = topo_node_registry_find(detector->instance->topo_groups, connection->peer_node_id); |
|
|
|
|
if (!node || !node->timestamp || memcmp(node->public_key, connection->crypto_ctx.peer_public_key, 32)) return; |
|
|
|
|
for (struct ETCP_LINK *link = connection->links; link; link = link->next) { |
|
|
|
|
struct ETCP_SOCKET *socket = link->conn; |
|
|
|
|
if (!socket || link->is_tcp || !link->init_retry_count || link->link_status || socket->probe_only || socket->socks_udp || |
|
|
|
|
socket->type == CFG_SERVER_TYPE_LOCAL || socket->type == CFG_SERVER_TYPE_PRIVATE) continue; |
|
|
|
|
const struct address_profile *profile = NULL; uint8_t target_socket = 0, config_type = CFG_SERVER_TYPE_UNKNOWN, type = 0; |
|
|
|
|
for (const struct TOPO_ADDR4 *a = node->v4_addrs; a; a = a->next) { |
|
|
|
|
const struct sockaddr_in *target = (const struct sockaddr_in *)&link->remote_addr; |
|
|
|
|
if (link->remote_addr.ss_family != AF_INET || !(a->protocol & TOPO_PROTO_UDP) || |
|
|
|
|
a->port != ntohs(target->sin_port) || memcmp(a->addr, &target->sin_addr, 4)) continue; |
|
|
|
|
for (const struct TOPO_SOCKMETA4 *m = node->v4_sock_meta; m; m = m->next) |
|
|
|
|
if (m->id == a->socket_id) { profile = &m->address_profile; config_type = m->config_type; break; } |
|
|
|
|
target_socket = a->socket_id; type = a->type; break; |
|
|
|
|
} |
|
|
|
|
for (const struct TOPO_ADDR6 *a = node->v6_addrs; a; a = a->next) { |
|
|
|
|
const struct sockaddr_in6 *target = (const struct sockaddr_in6 *)&link->remote_addr; |
|
|
|
|
if (link->remote_addr.ss_family != AF_INET6 || !(a->protocol & TOPO_PROTO_UDP) || |
|
|
|
|
a->port != ntohs(target->sin6_port) || memcmp(a->addr, &target->sin6_addr, 16)) continue; |
|
|
|
|
for (const struct TOPO_SOCKMETA6 *m = node->v6_sock_meta; m; m = m->next) |
|
|
|
|
if (m->id == a->socket_id) { profile = &m->address_profile; config_type = m->config_type; break; } |
|
|
|
|
target_socket = a->socket_id; type = a->type; break; |
|
|
|
|
} |
|
|
|
|
uint8_t target_class = sock_target_class(type, config_type, profile, public_address(detector, &link->remote_addr)); |
|
|
|
|
if (target_class != SOCK_TC_PUB && !(reverse_done && target_class == SOCK_TC_CONTACT)) continue; |
|
|
|
|
struct nat_socket *state = socket_state(detector, socket, 1); |
|
|
|
|
if (!schedule_failure_recheck(state, connection->peer_node_id, 0)) continue; |
|
|
|
|
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 (!control_route(detector, group->group_id, connection->peer_node_id)) continue; |
|
|
|
|
struct nat_recheck_wire request = {.cmd = ETCP_RT_ID_NAT_DETECTION, .command = NAT_RECHECK, |
|
|
|
|
.version = NAT_WIRE_VERSION, .socket_id = target_socket}; |
|
|
|
|
if (route_ping_addr_encode(request.address, &link->remote_addr)) break; |
|
|
|
|
struct ll_entry *packet = ll_alloc_lldgram(1 + sizeof(request)); |
|
|
|
|
if (!packet) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "NAT failure recheck allocation failed"); break; } |
|
|
|
|
packet->dgram[0] = ETCP_RT_ID_NAT_DETECTION; memcpy(packet->dgram + 1, &request, sizeof(request)); |
|
|
|
|
if (etcp_route_send(detector->instance, group->group_id, connection->peer_node_id, packet, 0, |
|
|
|
|
ROUTE_CRYPTO_SIGN | ROUTE_CRYPTO_ENCRYPT)) |
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_NAT, "NAT failure recheck forwarding failed group=%016llx peer=%016llx", |
|
|
|
|
(unsigned long long)group->group_id, (unsigned long long)connection->peer_node_id); |
|
|
|
|
else DEBUG_INFO(DEBUG_CATEGORY_NAT, "NAT failure recheck sent group=%016llx peer=%016llx endpoint=%s", |
|
|
|
|
(unsigned long long)group->group_id, (unsigned long long)connection->peer_node_id, |
|
|
|
|
sockaddr_storage_to_str(&link->remote_addr).str); |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static void connection_status(struct ETCP_CONN *connection, int status, void *arg) { |
|
|
|
|
struct NAT_DETECTION *detector = arg; |
|
|
|
|
if (status == ETCP_CONN_STATUS_DOWN || status == ETCP_CONN_STATUS_DELETE || status == ETCP_CONN_STATUS_REINIT) |
|
|
|
|
|