From 625382de345abce73f8957bec0db17a7fb442165 Mon Sep 17 00:00:00 2001 From: evgeny Date: Sat, 1 Aug 2026 12:34:53 +0300 Subject: [PATCH] node_conn_direct: add specific_sock param, move registry to per-instance; expose sc_hex_to_binary; add CONFIG_CONN_HANDLE --- AGENTS.md | 11 +++------ src/transport_layer/node_conn_direct.h | 31 +++++++++++++++----------- src/transport_layer/secure_channel.c | 8 +++---- src/transport_layer/secure_channel.h | 2 ++ src/utun_instance.h | 16 +++++++++++++ tests/test_node_conn_direct.c | 22 +++++++++--------- 6 files changed, 54 insertions(+), 36 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index c2860d8b..8936a48a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -20,6 +20,8 @@ This file contains essential information for AI coding agents working in the uTu Новый код обязательно должен иметь логи показывающие его правильное функционирование. Все ошибки и нештатное поведение должно логироваться +Ты постоянно тупишь на отладке и раздалбываешь код. Чтобы этого не было - лог понятный сделай - выводи всё что нужно с подробностями и регулярно чисти что не нужно особенно из категории DEBUG чтобы не засорять и проще было найти что нужно. И всё бустро найдешь. И нечего гадать когда можно просто посмотреть нормальный, правильно сделанный лог и сразу УВИДЕТЬ проблему не гадать, ошибаться, запарывать код еще сильнее и застревать в куче говна + ## Quick Reference **Repository:** uTun - Secure VPN tunnel with ETCP protocol @@ -80,7 +82,7 @@ ASAN_OPTIONS=detect_leaks=0:halt_on_error=0 ./src/utun -f -p /tmp/utun.pid -l /t ### Run All Tests ```bash -make check # Run all tests via automake, логи в tests/logs/ - запускай после make без grep, вывод короткий +make check # Run all tests via automake, логи в tests/logs/ - запускай тесты с ПОЛНЫМ ВЫОДОМ, не урезая его ( grep итд) - иначе будешь 10 раз повторять зпауск что жрёт много времени ``` ```powershell powershell check.bat # Windows, запускает каждый .exe из tests/ @@ -89,14 +91,7 @@ powershell check.bat # Windows, запускает каждый .exe ### Run Specific Test ```bash cd tests/ -./test_etcp_crypto ./test_etcp_two_instances -./test_etcp_simple_traffic -./test_pkt_normalizer_etcp -./test_etcp_api -./test_ll_queue -./test_nat_detection -./test_bgp_route_exchange ``` ### Run Single Test with Debug Info diff --git a/src/transport_layer/node_conn_direct.h b/src/transport_layer/node_conn_direct.h index d65ec03d..9fd48541 100644 --- a/src/transport_layer/node_conn_direct.h +++ b/src/transport_layer/node_conn_direct.h @@ -6,40 +6,45 @@ struct UTUN_INSTANCE; struct ETCP_CONN; struct TOPO_NODE; +struct ETCP_SOCKET; /* ─── Return codes ─── */ -#define NCD_NEW 0 -#define NCD_REUSED 1 -#define NCD_ERR -1 +#define NCD_NEW 0 /* создано новое соединение */ +#define NCD_REUSED 1 /* переиспользовано существующее */ +#define NCD_ERR -1 /* ошибка */ /* ─── Opaque handle ─── */ struct NODE_CONN_DIRECT; /* ─── Callback events (единый callback на handle) ─── */ enum ncd_event { - NCD_EVENT_UP = 0, - NCD_EVENT_DOWN = 1, - NCD_EVENT_TIMEOUT = 2, + NCD_EVENT_UP = 0, /* соединение поднялось (линки работают) */ + NCD_EVENT_DOWN = 1, /* соединение упало */ + NCD_EVENT_TIMEOUT = 2, /* таймаут первого подключения */ }; typedef void (*ncd_callback)(struct NODE_CONN_DIRECT* h, enum ncd_event event, void* arg); /* * Открыть handle к узлу по node_id. - * Node info — из node_registry, fallback SQLite. - * cb — вызывается при каждом изменении статуса / таймауте. - * Если conn уже готов — cb(h, NCD_EVENT_UP) через uasync_call_soon (не синхронно). - * - * Возвращает NCD_NEW / NCD_REUSED / NCD_ERR. + * Node info ищется через node_registry, fallback — SQLite. + * cb вызывается при изменении статуса / таймауте. + * Если conn уже готов — cb(NCD_EVENT_UP) через uasync_call_soon (не синхронно). */ int node_conn_direct_open(struct UTUN_INSTANCE* inst, uint64_t node_id, ncd_callback cb, void* cb_arg, - struct NODE_CONN_DIRECT** out_handle); + struct NODE_CONN_DIRECT** out_handle, + struct ETCP_SOCKET* specific_sock); /* NULL — авто-подбор всех совместимых сокетов для линков */ +/* + * То же, но с уже загруженным TOPO_NODE (ni не владеем — можно передать временный на стеке). + * ni должен содержать public_key, v4_addrs/v6_addrs для создания линков. + */ int node_conn_direct_open_node(struct UTUN_INSTANCE* inst, uint64_t node_id, ncd_callback cb, void* cb_arg, struct NODE_CONN_DIRECT** out_handle, - struct TOPO_NODE* ni); + struct TOPO_NODE* ni, /* публичный ключ + адреса пира (не владеем) */ + struct ETCP_SOCKET* specific_sock); /* NULL — авто-подбор */ void node_conn_direct_close(struct NODE_CONN_DIRECT* h); diff --git a/src/transport_layer/secure_channel.c b/src/transport_layer/secure_channel.c index 19a15aee..6b016cbd 100644 --- a/src/transport_layer/secure_channel.c +++ b/src/transport_layer/secure_channel.c @@ -34,7 +34,7 @@ static void sc_init_random_seed(void) } // Конвертация hex строки в бинарный формат -static int hex_to_binary(const char *hex_str, uint8_t *binary, size_t binary_len) { +int sc_hex_to_binary(const char *hex_str, uint8_t *binary, size_t binary_len) { if (!hex_str || !binary || strlen(hex_str) != binary_len * 2) return -1; for (size_t i = 0; i < binary_len; i++) { unsigned int byte; @@ -166,11 +166,11 @@ sc_status_t sc_init_local_keys(struct SC_MYKEYS *mykeys, const char *public_key, } DEBUG_INFO(DEBUG_CATEGORY_CRYPTO, "public_key len=%zu, private_key len=%zu", strlen(public_key), strlen(private_key)); - if (hex_to_binary(public_key, mykeys->public_key, SC_PUBKEY_SIZE)) { + if (sc_hex_to_binary(public_key, mykeys->public_key, SC_PUBKEY_SIZE)) { DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "failed to convert public key from hex"); return SC_ERR_INVALID_ARG; } - if (hex_to_binary(private_key, mykeys->private_key, SC_PRIVKEY_SIZE)) { + if (sc_hex_to_binary(private_key, mykeys->private_key, SC_PRIVKEY_SIZE)) { DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "failed to convert private key from hex"); return SC_ERR_INVALID_ARG; } @@ -185,7 +185,7 @@ sc_status_t sc_init_local_keys(struct SC_MYKEYS *mykeys, const char *public_key, sc_status_t sc_set_peer_public_key(sc_context_t *ctx, const uint8_t *peer_public_key_h, int mode) { uint8_t peer_public_key[SC_PUBKEY_SIZE]; if (mode) { - if (hex_to_binary((const char*)peer_public_key_h, peer_public_key, SC_PUBKEY_SIZE)) { + if (sc_hex_to_binary((const char*)peer_public_key_h, peer_public_key, SC_PUBKEY_SIZE)) { DEBUG_ERROR(DEBUG_CATEGORY_CRYPTO, "invalid hex key format"); return SC_ERR_INVALID_ARG; } diff --git a/src/transport_layer/secure_channel.h b/src/transport_layer/secure_channel.h index d086d9cc..9ded9a62 100644 --- a/src/transport_layer/secure_channel.h +++ b/src/transport_layer/secure_channel.h @@ -116,6 +116,8 @@ sc_status_t sc_derive_ed25519_pubkey(const uint8_t *x25519_privkey, uint8_t *ed2 uint64_t sc_derive_node_id_from_pubkey(const uint8_t *public_key); +int sc_hex_to_binary(const char *hex_str, uint8_t *binary, size_t binary_len); + #ifdef __cplusplus } diff --git a/src/utun_instance.h b/src/utun_instance.h index a3329f9b..9dc415dc 100644 --- a/src/utun_instance.h +++ b/src/utun_instance.h @@ -37,6 +37,7 @@ struct ETCP_CONN; typedef void (*etcp_new_conn_fn)(struct ETCP_CONN* conn, void* arg); struct ETCP_SOCKET; struct TCP_SOCKET; +struct NODE_CONN_DIRECT; struct tun_if; struct ETCP_BINDINGS; struct ETCP_ROUTER_BINDINGS; @@ -64,6 +65,14 @@ struct conn_queue_entry { struct ETCP_CONN* conn; }; +// Handle for config-based connections via node_conn_direct +struct CONFIG_CONN_HANDLE { + uint64_t node_id; + char name[MAX_CONN_NAME_LEN]; + struct NODE_CONN_DIRECT* handle; + struct CONFIG_CONN_HANDLE* next; +}; + // Queue entry for instance->tcp_connections (indexed by node_id) struct tcp_conn_entry { uint64_t node_id; // index key @@ -178,6 +187,13 @@ struct UTUN_INSTANCE { // NTP time synchronization struct NTP_TIME ntp; struct NTP_NODE_TIME ntp_node; + + // Config-based connection handles (node_conn_direct) + struct CONFIG_CONN_HANDLE* config_conn_handles; + + // Per-instance NCD state (replaces global statics in node_conn_direct.c) + void* ncd_registry; // struct ncd_entry* linked list + uint8_t ncd_control_bound; // 1 = etcp_bind(ETCP_RT_ID_NCD_CONTROL) сделан }; // Functions diff --git a/tests/test_node_conn_direct.c b/tests/test_node_conn_direct.c index 87ec5ca7..8cf43c12 100644 --- a/tests/test_node_conn_direct.c +++ b/tests/test_node_conn_direct.c @@ -100,11 +100,11 @@ static void t1(void* arg) { fprintf(stderr, "\n=== P1: two opens before poll ===\n"); fflush(stderr); g_a->etcp_connect_timeout_tb = TIMEOUT_TB; - int r = node_conn_direct_open(g_a, nid_b, ncd_cb, (void*)0, &gh[0]); + int r = node_conn_direct_open(g_a, nid_b, ncd_cb, (void*)0, &gh[0], NULL); fprintf(stderr, " open#0 → %s\n", r == NCD_NEW ? "NCD_NEW" : r == NCD_REUSED ? "NCD_REUSED" : "ERR"); if (r != NCD_NEW) { fail("expected NCD_NEW"); return; } - r = node_conn_direct_open(g_a, nid_b, ncd_cb, (void*)1, &gh[1]); + r = node_conn_direct_open(g_a, nid_b, ncd_cb, (void*)1, &gh[1], NULL); fprintf(stderr, " open#1 → %s\n", r == NCD_NEW ? "NCD_NEW" : r == NCD_REUSED ? "NCD_REUSED" : "ERR"); if (r != NCD_REUSED) { fail("expected NCD_REUSED"); return; } @@ -125,7 +125,7 @@ static void t2(void* arg) { static void t3(void* arg) { (void)arg; g_phase = 3; fprintf(stderr, "\n=== P3: open on ready conn ===\n"); fflush(stderr); - int r = node_conn_direct_open(g_a, nid_b, ncd_cb, (void*)2, &gh[2]); + int r = node_conn_direct_open(g_a, nid_b, ncd_cb, (void*)2, &gh[2], NULL); fprintf(stderr, " open#2 → %s\n", r == NCD_REUSED ? "NCD_REUSED" : "?"); if (r != NCD_REUSED) { fail("expected NCD_REUSED"); return; } uasync_call_soon(ua, NULL, t4); @@ -135,7 +135,7 @@ static void t4(void* arg) { (void)arg; g_phase = 4; if (g_up[2] == 0) { uasync_set_timeout(ua, POLL_MS, NULL, (timeout_callback_t)t4, "t4"); return; } fprintf(stderr, "\n=== P4: async cb OK, open h3 ===\n"); fflush(stderr); - int r = node_conn_direct_open(g_a, nid_b, ncd_cb, (void*)3, &gh[3]); + int r = node_conn_direct_open(g_a, nid_b, ncd_cb, (void*)3, &gh[3], NULL); fprintf(stderr, " open#3 → %s\n", r == NCD_REUSED ? "NCD_REUSED" : "?"); if (r != NCD_REUSED) { fail("expected NCD_REUSED"); return; } uasync_call_soon(ua, NULL, t5); @@ -158,10 +158,10 @@ static void t5(void* arg) { static void t6a(void* arg) { (void)arg; g_phase = 16; fprintf(stderr, "\n=== P6a: bidirectional — B opens handle to A ===\n"); fflush(stderr); - int r = node_conn_direct_open(g_b, nid_a, ncd_cb_b, (void*)0, &gh_b[0]); + int r = node_conn_direct_open(g_b, nid_a, ncd_cb_b, (void*)0, &gh_b[0], NULL); if (r != NCD_REUSED) { fail("P6a: B open expected NCD_REUSED (incoming conn exists)"); return; } fprintf(stderr, " B open → NCD_REUSED\n"); - r = node_conn_direct_open(g_a, nid_b, ncd_cb, (void*)4, &gh[4]); + r = node_conn_direct_open(g_a, nid_b, ncd_cb, (void*)4, &gh[4], NULL); if (r != NCD_REUSED) { fail("P6a: A open(4) expected NCD_REUSED (conn alive)"); return; } fprintf(stderr, " A open(4) → NCD_REUSED\n"); fflush(stderr); uasync_call_soon(ua, NULL, t6b); @@ -181,7 +181,7 @@ static void t6b(void* arg) { static void t6c(void* arg) { (void)arg; g_phase = 18; fprintf(stderr, "\n=== P6c: KEEP_ALIVE round-trip, A re-opens ===\n"); fflush(stderr); - int r = node_conn_direct_open(g_a, nid_b, ncd_cb, (void*)5, &gh[5]); + int r = node_conn_direct_open(g_a, nid_b, ncd_cb, (void*)5, &gh[5], NULL); if (r != NCD_REUSED) { fail("P6c: expected NCD_REUSED (KEEP_ALIVE saved conn)"); return; } fprintf(stderr, " A re-open(5) → NCD_REUSED\n"); fflush(stderr); uasync_call_soon(ua, NULL, t6d); @@ -203,7 +203,7 @@ static void t6e(void* arg) { (void)arg; g_phase = 20; fprintf(stderr, "\n=== P6e: close h1 → fin_wait, immediately re-open ===\n"); fflush(stderr); node_conn_direct_close(gh[1]); gh[1] = NULL; - int r = node_conn_direct_open(g_a, nid_b, ncd_cb, (void*)4, &gh[4]); + int r = node_conn_direct_open(g_a, nid_b, ncd_cb, (void*)4, &gh[4], NULL); if (r != NCD_REUSED) { fail("P6e: expected NCD_REUSED (entry found, fin_wait cleared)"); return; } fprintf(stderr, " re-open → NCD_REUSED\n"); fflush(stderr); uasync_call_soon(ua, NULL, t6f); @@ -231,7 +231,7 @@ static void t7(void* arg) { (void)arg; g_phase = 7; fprintf(stderr, "\n=== P7: NCD_ERR unknown node ===\n"); fflush(stderr); struct NODE_CONN_DIRECT* hx = NULL; - int r = node_conn_direct_open(g_a, 0xDEADBEEF00000001ULL, ncd_cb, (void*)99, &hx); + int r = node_conn_direct_open(g_a, 0xDEADBEEF00000001ULL, ncd_cb, (void*)99, &hx, NULL); fprintf(stderr, " open(unknown) → %s\n", r == NCD_ERR ? "NCD_ERR" : "?"); if (r != NCD_ERR) { fail("expected NCD_ERR"); return; } if (hx != NULL) { fail("handle not NULL"); return; } @@ -261,7 +261,7 @@ static void t8(void* arg) { memset((void*)g_tout, 0, sizeof(g_tout)); g_a->etcp_connect_timeout_tb = SHORT_TO_TB; - int r = node_conn_direct_open(g_a, fake_id, ncd_cb, (void*)0, &gh[0]); + int r = node_conn_direct_open(g_a, fake_id, ncd_cb, (void*)0, &gh[0], NULL); fprintf(stderr, " open(unreachable) → %s\n", r == NCD_NEW ? "NCD_NEW" : "?"); if (r != NCD_NEW) { fail("expected NCD_NEW"); return; } @@ -309,7 +309,7 @@ static int setup(void) { static void cleanup(void) { test_unlink(ca); test_unlink(cb); test_rmdir(tdir); } int main(void) { - debug_config_init(); debug_set_level(DEBUG_LEVEL_WARN); + debug_config_init(); debug_set_level(DEBUG_LEVEL_TRACE); utun_instance_set_tun_init_enabled(0); if (setup() != 0) return 1; ua = uasync_create();