diff --git a/src/control_server.c b/src/control_server.c index e4b1ef21..39d88e5c 100644 --- a/src/control_server.c +++ b/src/control_server.c @@ -613,7 +613,7 @@ static void handle_client_data(struct control_server* server, struct control_cli close_client(server, client); return; } - if (hdr->type < ETCPMON_CMD_LIST_CONN || hdr->type > ETCPMON_CMD_LIST_SOCKETS) { + if (hdr->type < ETCPMON_CMD_LIST_CONN || hdr->type > ETCPMON_CMD_ACTION) { DEBUG_ERROR(DEBUG_CATEGORY_CONTROL, "Invalid command type from client: 0x%02X", hdr->type); close_client(server, client); return; @@ -684,6 +684,18 @@ static void handle_client_data(struct control_server* server, struct control_cli send_socket_list(server, client, req_seq); break; + case ETCPMON_CMD_ACTION: + if (payload_size >= sizeof(struct etcpmon_cmd_action)) { + struct etcpmon_cmd_action* cmd = (struct etcpmon_cmd_action*)payload; + if (strncmp(cmd->action, "nat", 3) == 0) { + DEBUG_INFO(DEBUG_CATEGORY_CONTROL, "Action 'nat' received, requesting NAT check for all links"); + route_bgp_request_nat_check_all(server->instance->bgp); + } else { + DEBUG_WARN(DEBUG_CATEGORY_CONTROL, "Unknown action received: '%s'", cmd->action); + } + } + break; + case ETCPMON_CMD_DISCONNECT: if (server->log_file) { fprintf(server->log_file, "%llu: [LOG] Client requested disconnect\n", diff --git a/src/route_bgp.c b/src/route_bgp.c index 9e7c8968..57847900 100644 --- a/src/route_bgp.c +++ b/src/route_bgp.c @@ -113,7 +113,7 @@ static void route_bgp_broadcast_withdraw(struct ROUTE_BGP* bgp, uint64_t node_id // Приём пакетов // ============================================================================ -static void route_bgp_start_link_nat_check(struct ROUTE_BGP* bgp, struct ETCP_LINK* link); +void route_bgp_start_link_nat_check(struct ROUTE_BGP* bgp, struct ETCP_LINK* link); static void route_bgp_handle_nat_info(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn, const uint8_t* data, size_t len); static void route_bgp_handle_nat_check_req(struct ROUTE_BGP* bgp, struct ETCP_CONN* from_conn, const uint8_t* data, size_t len); @@ -596,7 +596,7 @@ static void route_bgp_extract_nat_addr(struct ETCP_CONN* conn, uint32_t* nat_ip, } } -static void route_bgp_start_link_nat_check(struct ROUTE_BGP* bgp, struct ETCP_LINK* link) {// проверяем тип нат для линка link +void route_bgp_start_link_nat_check(struct ROUTE_BGP* bgp, struct ETCP_LINK* link) {// проверяем тип нат для линка link if (!bgp || !link || !link->conn || !link->etcp) return; if (link->nat_check_status == NAT_CHECK_IN_PROGRESS) return; // Find third node to send ping through @@ -1095,3 +1095,19 @@ void route_bgp_send_nat_check_req(struct ETCP_CONN* conn, uint8_t socket_id) { ip_to_str(&pkt->interface_ip, AF_INET).str, (unsigned)ntohs(pkt->interface_port)); } + +void route_bgp_request_nat_check_all(struct ROUTE_BGP* bgp) { + if (!bgp || !bgp->instance) return; + int count = 0; + struct ETCP_CONN* conn = bgp->instance->connections; + while (conn) { + struct ETCP_LINK* link = conn->links; + while (link) { + route_bgp_start_link_nat_check(bgp, link); + count++; + link = link->next; + } + conn = conn->next; + } + DEBUG_INFO(DEBUG_CATEGORY_BGP, "NAT check requested for all links, count=%d", count); +} diff --git a/src/route_bgp.h b/src/route_bgp.h index 3b473f51..1a10b058 100644 --- a/src/route_bgp.h +++ b/src/route_bgp.h @@ -195,4 +195,9 @@ void route_bgp_send_nat_check_req(struct ETCP_CONN* conn, uint8_t socket_id); */ void route_bgp_set_nat_check_local(struct ROUTE_BGP* bgp, int allow); +/** + * @brief Запускает NAT check для всех линков всех соединений. + */ +void route_bgp_request_nat_check_all(struct ROUTE_BGP* bgp); + #endif // ROUTE_BGP_H diff --git a/src/route_ping.c b/src/route_ping.c index f2a9e6e5..ec5b1f3f 100644 --- a/src/route_ping.c +++ b/src/route_ping.c @@ -227,7 +227,7 @@ static void route_ping_single_cb(int success, ctx->sum_rtt += rtt; } - DEBUG_INFO(DEBUG_CATEGORY_BGP, "ping response id=%zu", request_id); + DEBUG_INFO(DEBUG_CATEGORY_BGP, "ping response nonce=%llu", (unsigned long long)nonce); /* Если ещё не все пакеты отправлены — сразу шлём следующий */ if (ctx->count_sent < ctx->count_total) { diff --git a/tests/Makefile.am b/tests/Makefile.am index 961bc337..45567371 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -91,6 +91,7 @@ ETCP_FULL_OBJS = \ $(top_builddir)/src/utun-tun_route.o \ $(top_builddir)/src/utun-packet_dump.o \ $(top_builddir)/src/utun-firewall.o \ + $(top_builddir)/src/utun-control_server.o \ $(TUN_PLATFORM_OBJ) \ $(top_builddir)/src/utun-utun_instance.o \ $(ETCP_CORE_OBJS) @@ -103,7 +104,7 @@ WIN_LIBS = endif # Common libraries (libuasync.a from lib directory) -COMMON_LIBS = $(top_builddir)/src/utun-control_server.o $(top_builddir)/lib/libuasync.a -lpthread $(WIN_LIBS) +COMMON_LIBS = $(top_builddir)/lib/libuasync.a -lpthread $(WIN_LIBS) # Crypto libraries (conditional) if USE_OPENSSL diff --git a/tools/etcpmon/etcpmon_client.c b/tools/etcpmon/etcpmon_client.c index d49a35fa..aa842b82 100644 --- a/tools/etcpmon/etcpmon_client.c +++ b/tools/etcpmon/etcpmon_client.c @@ -355,6 +355,47 @@ int etcpmon_client_request_metrics(struct etcpmon_client* client) { return 0; } +int etcpmon_client_send_action(struct etcpmon_client* client, const char* action) { + if (!client || client->sock == INVALID_SOCKET || !action) return -1; + + struct etcpmon_cmd_action cmd; + memset(&cmd, 0, sizeof(cmd)); + strncpy(cmd.action, action, sizeof(cmd.action) - 1); + cmd.action[sizeof(cmd.action) - 1] = '\0'; + + struct etcpmon_msg_header hdr; + etcpmon_build_header(&hdr, sizeof(cmd), ETCPMON_CMD_ACTION, 0); + + if (client->log_file) { + log_hex_data(client->log_file, "TX", (const uint8_t*)&hdr, sizeof(hdr)); + fprintf(client->log_file, "%llu: [LOG] CMD_ACTION '%s'\n", + (unsigned long long)get_timestamp_ms(), cmd.action); + fflush(client->log_file); + } + + int sent = send(client->sock, (const char*)&hdr, sizeof(hdr), 0); + if (sent != sizeof(hdr)) { + if (client->log_file) { + fprintf(client->log_file, "%llu: [ERROR] Failed to send CMD_ACTION header: %d\n", + (unsigned long long)get_timestamp_ms(), WSAGetLastError()); + fflush(client->log_file); + } + return -1; + } + + sent = send(client->sock, (const char*)&cmd, sizeof(cmd), 0); + if (sent != sizeof(cmd)) { + if (client->log_file) { + fprintf(client->log_file, "%llu: [ERROR] Failed to send CMD_ACTION payload: %d\n", + (unsigned long long)get_timestamp_ms(), WSAGetLastError()); + fflush(client->log_file); + } + return -1; + } + + return 0; +} + /* Send request with callback - queued version */ int etcpmon_client_send_request(struct etcpmon_client* client, uint8_t type, diff --git a/tools/etcpmon/etcpmon_client.h b/tools/etcpmon/etcpmon_client.h index f44389b6..a5c653fb 100644 --- a/tools/etcpmon/etcpmon_client.h +++ b/tools/etcpmon/etcpmon_client.h @@ -186,6 +186,9 @@ struct metrics_history* etcpmon_client_get_history(struct etcpmon_client* client /* Add metrics to history */ void etcpmon_client_add_to_history(struct etcpmon_client* client, struct etcpmon_rsp_metrics* metrics); +/* Send action command to server */ +int etcpmon_client_send_action(struct etcpmon_client* client, const char* action); + uint64_t get_timestamp_ms(void); // Add this declaration #ifdef __cplusplus diff --git a/tools/etcpmon/etcpmon_gui.c b/tools/etcpmon/etcpmon_gui.c index b128a730..84fa2861 100644 --- a/tools/etcpmon/etcpmon_gui.c +++ b/tools/etcpmon/etcpmon_gui.c @@ -30,6 +30,7 @@ static void CreateControls(struct etcpmon_app* app); static void OnConnect(struct etcpmon_app* app); static void OnDisconnect(struct etcpmon_app* app); static void OnConnectionSelect(struct etcpmon_app* app); +static void OnAction(struct etcpmon_app* app); static void OnTimer(struct etcpmon_app* app); static void UpdateUIState(struct etcpmon_app* app); static void AddTooltip(HWND hTip, HWND hCtrl, const char* text); @@ -212,6 +213,19 @@ static void CreateControls(struct etcpmon_app* app) { WS_CHILD | WS_VISIBLE | LBS_NOTIFY | WS_VSCROLL | LBS_NOINTEGRALHEIGHT, x + 310, y + 20, 300, 120, hWnd, (HMENU)IDC_LIST_SOCKETS, hInst, NULL); + /* Action input */ + CreateWindowExA(0, "STATIC", "Action:", + WS_CHILD | WS_VISIBLE, + x + 620, y, 80, 20, hWnd, (HMENU)IDC_STATIC, hInst, NULL); + + app->hEditAction = CreateWindowExA(WS_EX_CLIENTEDGE, "EDIT", "", + WS_CHILD | WS_VISIBLE | ES_AUTOHSCROLL, + x + 620, y + 20, 200, 22, hWnd, (HMENU)IDC_EDIT_ACTION, hInst, NULL); + + app->hBtnAction = CreateWindowExA(0, "BUTTON", "Send", + WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, + x + 830, y + 19, 60, 24, hWnd, (HMENU)IDC_BTN_ACTION, hInst, NULL); + /* Graph area */ y += 140; app->hGraphWnd = CreateWindowExA( @@ -940,6 +954,9 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM l OnConnectionSelect(app); } break; + case IDC_BTN_ACTION: + OnAction(app); + break; } } break; @@ -1019,6 +1036,19 @@ static void OnConnectionSelect(struct etcpmon_app* app) { } } +static void OnAction(struct etcpmon_app* app) { + if (!app || !app->client || !app->hEditAction) return; + + char action[33]; + GetWindowTextA(app->hEditAction, action, sizeof(action)); + action[sizeof(action) - 1] = '\0'; + + if (strlen(action) > 0) { + etcpmon_client_send_action(app->client, action); + SetWindowTextA(app->hEditAction, ""); + } +} + static void OnTimer(struct etcpmon_app* app) { if (!app || !app->client) return; diff --git a/tools/etcpmon/etcpmon_gui.h b/tools/etcpmon/etcpmon_gui.h index f7e55acf..bae55f5c 100644 --- a/tools/etcpmon/etcpmon_gui.h +++ b/tools/etcpmon/etcpmon_gui.h @@ -41,6 +41,10 @@ extern "C" { #define IDC_LIST_SOCKETS 106 #define IDC_TIMER_UPDATE 105 +/* Action control IDs */ +#define IDC_EDIT_ACTION 107 +#define IDC_BTN_ACTION 108 + /* ETCP Metrics control IDs */ #define IDC_EDIT_ETCP_NAME 200 #define IDC_EDIT_ETCP_RTT_LAST 201 @@ -197,6 +201,8 @@ struct etcpmon_app { HWND hBtnDisconnect; HWND hListConnections; HWND hListSockets; + HWND hEditAction; + HWND hBtnAction; /* ETCP metrics controls */ HWND hEditEtcpName; diff --git a/tools/etcpmon/etcpmon_protocol.h b/tools/etcpmon/etcpmon_protocol.h index 23dc61d6..881a550d 100644 --- a/tools/etcpmon/etcpmon_protocol.h +++ b/tools/etcpmon/etcpmon_protocol.h @@ -49,6 +49,7 @@ extern "C" { #define ETCPMON_CMD_GET_METRICS 0x03 /* Request metrics for selected */ #define ETCPMON_CMD_DISCONNECT 0x04 /* Disconnect from monitoring */ #define ETCPMON_CMD_LIST_SOCKETS 0x05 /* Request local socket list */ +#define ETCPMON_CMD_ACTION 0x06 /* Execute action (text command) */ /* Server -> Client responses */ #define ETCPMON_RSP_CONN_LIST 0x81 /* Connection list response */ @@ -86,6 +87,11 @@ struct etcpmon_cmd_select { uint64_t peer_node_id; /* peer_node_id of connection to monitor */ }; +/* CMD_ACTION: Execute action command */ +struct etcpmon_cmd_action { + char action[32]; /* Null-terminated action string */ +}; + /* CMD_GET_METRICS: No payload required (uses previously selected connection) */ /* CMD_DISCONNECT: No payload required */