diff --git a/src/routing_layer/topo_node_sqlite.c b/src/routing_layer/topo_node_sqlite.c index 2c715997..fb54d470 100644 --- a/src/routing_layer/topo_node_sqlite.c +++ b/src/routing_layer/topo_node_sqlite.c @@ -1183,6 +1183,43 @@ struct TOPO_NODE* topo_node_sqlite_snapshot_load(sqlite3* db, struct TOPO_GROUPS return ni; } +/* LAN-подтверждение может дать первый адрес узлу, чьи ключи уже проверены member_sync. */ +struct TOPO_NODE* topo_node_sqlite_identity_load(sqlite3* db, uint64_t node_id) { + if (!db || !node_id) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "identity load: invalid arguments"); return NULL; } + sqlite3_stmt* stmt = NULL; + struct TOPO_NODE* ni = NULL; + const char* sql = "SELECT name,x25519_pubkey,ed25519_pubkey,client_type FROM nodes WHERE node_id=?"; + int rc = sqlite3_prepare_v2(db, sql, -1, &stmt, NULL); + if (rc == SQLITE_OK) rc = sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id); + if (rc == SQLITE_OK) rc = sqlite3_step(stmt); + if (rc == SQLITE_ROW) { + const uint8_t* x = sqlite3_column_blob(stmt, 1); + const uint8_t* ed = sqlite3_column_blob(stmt, 2); + if (!x || !ed || sqlite3_column_bytes(stmt, 1) != 32 || sqlite3_column_bytes(stmt, 2) != 32 || + sc_derive_node_id_from_pubkey(x) != node_id) { + DEBUG_WARN(DEBUG_CATEGORY_BGP, "identity load: invalid keys node=%016llx", (unsigned long long)node_id); + } else { + ni = u_calloc(1, sizeof(*ni)); + if (!ni) DEBUG_ERROR(DEBUG_CATEGORY_BGP, "identity load: allocation failed"); + else { + ni->node_id = node_id; ni->client_type = (uint8_t)sqlite3_column_int(stmt, 3); + memcpy(ni->public_key, x, 32); memcpy(ni->ed25519_public_key, ed, 32); + const char* name = (const char*)sqlite3_column_text(stmt, 0); + if (name && !(ni->node_name = u_strdup(name))) { + DEBUG_ERROR(DEBUG_CATEGORY_BGP, "identity load: name allocation failed"); u_free(ni); ni = NULL; + } + } + } + } else if (rc != SQLITE_DONE) DEBUG_ERROR(DEBUG_CATEGORY_BGP, "identity load: %s", sqlite3_errmsg(db)); + else DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "identity load: unknown node=%016llx", (unsigned long long)node_id); + if (sqlite3_finalize(stmt) != SQLITE_OK) { + DEBUG_ERROR(DEBUG_CATEGORY_BGP, "identity load finalize: %s", sqlite3_errmsg(db)); + topo_node_destroy(NULL, ni); ni = NULL; + } + if (ni) DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "identity loaded without addresses node=%016llx", (unsigned long long)node_id); + return ni; +} + struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* groups, uint64_t node_id) { if (!db || !groups || !groups->instance || groups->instance->topo_groups != groups) { DEBUG_ERROR(DEBUG_CATEGORY_BGP, "node load: invalid database/groups node=%016llx", (unsigned long long)node_id); return NULL; diff --git a/src/routing_layer/topo_node_sqlite.h b/src/routing_layer/topo_node_sqlite.h index 6a2de302..2b587dcc 100644 --- a/src/routing_layer/topo_node_sqlite.h +++ b/src/routing_layer/topo_node_sqlite.h @@ -149,6 +149,10 @@ void topo_node_sqlite_update_rtt(sqlite3* db, uint64_t node_id, uint16_t rtt); * Вызывающий передаёт владение через topo_node_registry_store() либо вызывает topo_node_destroy(). */ struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* groups, uint64_t node_id); +/* Загрузить только известную идентичность nodes, без адресов/подписи/timestamp. + * Для NCD с независимо подтверждённым LAN-адресом. Проверяет размеры ключей и node_id=derive(X25519). + * Владельческий TOPO_NODE или NULL; уничтожить topo_node_destroy либо передать registry. */ +struct TOPO_NODE* topo_node_sqlite_identity_load(sqlite3* db, uint64_t node_id); /* Записать connected=0/1 существующего участника; 0/-1, без вставки отсутствующей строки. */ int topo_node_sqlite_set_connected(sqlite3* db, const char* channel_id, uint64_t node_id, int connected); diff --git a/src/transport_layer/etcp_connections.h b/src/transport_layer/etcp_connections.h index abfb444a..a8446c85 100644 --- a/src/transport_layer/etcp_connections.h +++ b/src/transport_layer/etcp_connections.h @@ -225,6 +225,8 @@ struct ETCP_LINK { struct ETCP_SOCKET* conn; // сокет через который работаем // Путь соединения struct sockaddr_storage remote_addr; // Удалённый адрес + uint64_t lan_generation; // ненулевое поколение неподтверждённой LAN-пробы; 0 = обычный линк + uint32_t lan_interface; // локальный интерфейс, через который подтверждён LAN-кандидат // Параметры соединения uint16_t mtu; // MTU общий