diff --git a/src/routing_layer/nat_detection.c b/src/routing_layer/nat_detection.c index c981b04b..54059339 100644 --- a/src/routing_layer/nat_detection.c +++ b/src/routing_layer/nat_detection.c @@ -1060,9 +1060,9 @@ static void owner_start(struct nat_socket *state) { state->using_fallback = 0; state->prefer_fresh = 1; } history_load(state); - if (select_pair(state)) { owner_finish(state, state->reason); return; } if (random_id(&state->round)) { owner_finish(state, NAT_REASON_SEND_ERROR); return; } state->rounds++; + if (select_pair(state)) { owner_finish(state, state->reason); return; } memset(&state->helper_seen, 0, sizeof(state->helper_seen)); memset(&state->alternate_seen, 0, sizeof(state->alternate_seen)); state->retries = 0; state->pre_received = 0; state->post_received = 0; state->filter_clean = 0; state->pre_healthy = 0; state->deadline = get_time_tb() + NAT_ROUND_TB; state->reason = NAT_REASON_NONE; diff --git a/tests/stream_netns/node.c b/tests/stream_netns/node.c index 1ad5f1d2..4aa2504b 100644 --- a/tests/stream_netns/node.c +++ b/tests/stream_netns/node.c @@ -199,9 +199,9 @@ static void statistics(struct lab *lab, uint64_t id, int loads) { stun.members, stun.generation, stun.evidence_id); json_string(sockaddr_storage_to_str(&stun.local).str); printf("}"); } - printf(",\"phase\":%u,\"reason\":\"%s\",\"observer\":\"%" PRIu64 "\",\"helper\":\"%" PRIu64 "\"," + printf(",\"phase\":%u,\"reason\":\"%s\",\"group\":\"%" PRIu64 "\",\"observer\":\"%" PRIu64 "\",\"helper\":\"%" PRIu64 "\"," "\"rounds\":%u,\"helper_reselections\":%u,\"history_complete\":%u,\"contacts\":[", status.phase, - nat_check_reason_name(status.reason), status.observer, status.helper, status.rounds, + nat_check_reason_name(status.reason), status.group_id, status.observer, status.helper, status.rounds, status.helper_reselections, status.history_complete); uint8_t local[ROUTE_ADDR_WIRE_SIZE]; sqlite3_stmt *contacts = NULL; int contact_separator = 0; if (!socket->is_tcp && !route_ping_addr_encode(local, &socket->local_addr) && @@ -322,6 +322,16 @@ static struct TOPO_NODE *parse_snapshot(struct lab *lab, const char *json) { /* Стенд переносит подписанные снимки через RPC только до запуска группы. * NCD handshake, наблюдения и весь трафик всё равно проходят по настоящей сети. */ +/* NAT-стенд имеет настоящую общую группу; UP прямого транспорта начинает групповой обмен. */ +static void nat_link_ready(struct NODE_CONN_DIRECT *handle, enum ncd_event event, void *arg) { + struct lab *lab = arg; + if (event != NCD_EVENT_UP) return; + struct TOPO_GROUP *group = topo_groups_find(lab->inst->topo_groups, TOPO_GROUP_UTUN); + struct ETCP_CONN *connection = node_conn_direct_get_conn(handle); + if (!group || !connection || topo_group_new_conn(group, connection)) + DEBUG_ERROR(DEBUG_CATEGORY_NAT, "lab: NAT group connection unavailable"); +} + static int nat_command(struct lab *lab, const char *json, const char *operation, uint64_t id) { if (!strcmp(operation, "chat_start")) { int result = chat_service_start(lab->inst); @@ -329,6 +339,7 @@ static int nat_command(struct lab *lab, const char *json, const char *operation, reply(id, result); return 1; } if (!strcmp(operation, "nat_release")) { + if (topo_groups_find(lab->inst->topo_groups, TOPO_GROUP_UTUN)) topo_groups_remove_group(lab->inst->topo_groups, TOPO_GROUP_UTUN); for (unsigned i = 0; i < lab->nat_handle_count; i++) node_conn_direct_close(lab->nat_handles[i]); for (unsigned i = 0; i < lab->nat_record_count; i++) topo_node_registry_unref(lab->inst->topo_groups, lab->nat_records[i]); lab->nat_handle_count = lab->nat_record_count = 0; reply(id, 0); return 1; @@ -369,7 +380,7 @@ static int nat_command(struct lab *lab, const char *json, const char *operation, if (!socket) { DEBUG_ERROR(DEBUG_CATEGORY_NAT, "lab: native link source/handle unavailable"); result = -1; } else { struct NODE_CONN_DIRECT *handle = NULL; - int opened = node_conn_direct_open_node(lab->inst, node->node_id, NULL, NULL, &handle, node, socket); + int opened = node_conn_direct_open_node(lab->inst, node->node_id, nat_link_ready, lab, &handle, node, socket); if (opened == NCD_ERR || !handle) result = -1; else lab->nat_handles[lab->nat_handle_count++] = handle; } @@ -518,7 +529,12 @@ int main(int argc, char **argv) { if (!lab->inst || utun_core_start(lab->inst) || (!core_only && chat_service_start(lab->inst))) { DEBUG_ERROR(DEBUG_CATEGORY_STREAM, "lab: service startup failed"); return 1; } - if (core_only) nat_detection_set_automatic(lab->inst->nat_det, 0); + if (core_only) { + nat_detection_set_automatic(lab->inst->nat_det, 0); + if (!topo_groups_create_group(lab->inst->topo_groups, TOPO_GROUP_UTUN, TOPO_GROUP_TYPE_UTUN, "")) { + DEBUG_ERROR(DEBUG_CATEGORY_NAT, "lab: NAT control group creation failed"); return 1; + } + } debug_enable_console(0); if (!core_only) stream_set_event_callback(lab->inst, event, lab); if (fcntl(STDIN_FILENO, F_SETFL, fcntl(STDIN_FILENO, F_GETFL) | O_NONBLOCK) < 0) {