#include #include #include #include "utun_instance.h" #include "config_parser.h" #include "routing_layer/topo_group.h" #include "transport_layer/etcp.h" #include "transport_layer/etcp_connections.h" #include "transport_layer/node_conn_direct.h" #include "../lib/u_async.h" #include "../lib/debug_config.h" static int links(struct ETCP_CONN* conn) { int count = 0; for (struct ETCP_LINK* link = conn->links; link; link = link->next) count++; return count; } static void endpoint(struct CFG_CLIENT_LINK* link, struct CFG_SERVER* local, int port) { memset(link, 0, sizeof(*link)); link->local_srv = local; struct sockaddr_in* addr = (struct sockaddr_in*)&link->remote_addr; addr->sin_family = AF_INET; addr->sin_addr.s_addr = htonl(0x7f000001); addr->sin_port = htons((uint16_t)port); } int main(void) { debug_config_init(); debug_set_level(DEBUG_LEVEL_INFO); utun_instance_set_tun_init_enabled(0); struct UASYNC* ua = uasync_create(); assert(ua); struct UTUN_INSTANCE* inst = utun_instance_create_from_str(ua, "[global]\n" "my_private_key=704f2e012c8fa8768130cb0f988a997dccb628372bc5ceccacc78dcbfec5916f\n" "my_public_key=b3193173def895bd0fcea6f86af077c7d77216f10395275f627ac18242ec0f01\n" "[server: udp]\naddr=127.0.0.1:0\ntype=public\n" "[server: tcp]\naddr=127.0.0.1:0\ntype=public\ntransport=tcp\n"); assert(inst && utun_instance_init(inst) >= 0); struct CFG_SERVER *udp = NULL, *tcp = NULL; for (struct CFG_SERVER* s = inst->config->servers; s; s = s->next) { if (!strcmp(s->name, "udp")) udp = s; if (!strcmp(s->name, "tcp")) tcp = s; } assert(udp && tcp); struct CFG_CLIENT client = { .name = "peer" }; struct SC_MYKEYS peer; assert(sc_generate_keypair(&peer) == SC_OK); for (int i = 0; i < 32; i++) snprintf(client.peer_public_key_hex + i * 2, 3, "%02x", peer.public_key[i]); struct CFG_CLIENT_LINK first, second, third; endpoint(&first, udp, 9); endpoint(&second, udp, 10); endpoint(&third, tcp, 11); first.next = &second; second.next = &third; client.links = &first; assert(init_client_connections(inst, &client) == 0); assert(inst->config_conn_handles && !inst->config_conn_handles->next); struct ETCP_CONN* conn = topo_group_peer_conn(inst->config_conn_handles->request); assert(conn && links(conn) == 3 && !conn->fin_wait); struct NODE_CONN_DIRECT* chat = NULL; assert(node_conn_direct_open(inst, conn->peer_node_id, NULL, NULL, &chat, NULL) == NCD_REUSED); assert(init_client_connections(inst, &client) == 0); assert(topo_group_peer_conn(inst->config_conn_handles->request) == conn && links(conn) == 3 && !conn->fin_wait); /* Ошибка нового набора не освобождает предыдущие handles. */ struct CFG_CLIENT invalid = { .name = "invalid", .peer_public_key_hex = "not-a-key" }; client.next = &invalid; struct CONFIG_CONN_HANDLE* previous = inst->config_conn_handles; assert(init_client_connections(inst, &client) < 0 && inst->config_conn_handles == previous); assert(node_conn_direct_get_conn(chat) == conn && !conn->fin_wait); client.next = NULL; /* REALITY идёт по тому же NCD пути; полное SNI не обрезается. */ client.links = &third; client.reality_enabled = 1; reality_client_config_set_defaults(&client.reality); memcpy(client.reality.server_static_pubkey, peer.public_key, 32); memset(client.reality.server_name, 'a', 180); client.reality.server_name[180] = 0; assert(init_client_connections(inst, &client) == 0); assert(links(conn) == 3); struct ETCP_LINK* real = NULL; for (struct ETCP_LINK* link = conn->links; link; link = link->next) if (link->is_tcp) real = link; assert(real && real->reality_set && !strcmp(real->reality.server_name, client.reality.server_name)); assert(init_client_connections(inst, &client) == 0 && links(conn) == 3); assert(init_client_connections(inst, NULL) == 0 && !inst->config_conn_handles); assert(node_conn_direct_get_conn(chat) == conn && !conn->fin_wait); node_conn_direct_force_close(chat); uasync_poll(ua, 0); /* Клиентский TCP/REALITY не требует локального TCP listen-сокета. */ struct ETCP_SOCKET* sock = inst->etcp_sockets; while (sock) { struct ETCP_SOCKET* next = sock->next; if (sock->is_tcp) etcp_socket_remove(sock); sock = next; } third.local_srv = NULL; assert(init_client_connections(inst, &client) == 0); conn = topo_group_peer_conn(inst->config_conn_handles->request); assert(conn && links(conn) == 1 && conn->links->is_tcp && !conn->links->conn); assert(conn->links->reality_set && !strcmp(conn->links->reality.server_name, client.reality.server_name)); assert(init_client_connections(inst, NULL) == 0); inst->running = 0; utun_instance_destroy(inst); uasync_poll(ua, 0); uasync_destroy(ua, 0); return 0; }