From 1f3f1d9a34b07b2a42bf36dde7c668a6773a4679 Mon Sep 17 00:00:00 2001 From: evgeny Date: Mon, 26 Oct 2026 12:23:59 +0100 Subject: [PATCH] Separate missing member verification keys from SQLite failures --- src/routing_layer/topo_node_sqlite.c | 57 +++++++++++++++++++--------- src/routing_layer/topo_node_sqlite.h | 11 +++++- 2 files changed, 48 insertions(+), 20 deletions(-) diff --git a/src/routing_layer/topo_node_sqlite.c b/src/routing_layer/topo_node_sqlite.c index 223863b9..d5ec47d9 100644 --- a/src/routing_layer/topo_node_sqlite.c +++ b/src/routing_layer/topo_node_sqlite.c @@ -876,18 +876,26 @@ int topo_node_sqlite_member_del(sqlite3* db, const char* channel_id, uint64_t no int topo_node_sqlite_channel_get(sqlite3* db, const char* channel_id, char* name_out, int name_sz, uint64_t* owner_node_id, uint8_t* x25519_pub, uint8_t* ed25519_pub, uint8_t* signature) { - if (!db || !channel_id) return -1; + if (!db || !channel_id) { + DEBUG_ERROR(DEBUG_CATEGORY_BGP, "channel lookup: invalid arguments"); return TOPO_SQLITE_LOOKUP_ERROR; + } sqlite3_stmt* stmt = NULL; - if (sqlite3_prepare_v2(db, + int rc = sqlite3_prepare_v2(db, "SELECT name, owner_node_id, x25519_pubkey, ed25519_pubkey, signature" - " FROM channels WHERE channel_id=?", -1, &stmt, NULL) != SQLITE_OK) return -1; - sqlite3_bind_text(stmt, 1, channel_id, -1, SQLITE_STATIC); - if (sqlite3_step(stmt) != SQLITE_ROW) { sqlite3_finalize(stmt); return -1; } - if ((x25519_pub && sqlite3_column_bytes(stmt, 2) != 32) || - (ed25519_pub && sqlite3_column_bytes(stmt, 3) != 32) || (signature && sqlite3_column_bytes(stmt, 4) != 64)) { - DEBUG_ERROR(DEBUG_CATEGORY_BGP, "invalid stored channel keys/signature channel=%s sizes=%d/%d/%d", channel_id, - sqlite3_column_bytes(stmt, 2), sqlite3_column_bytes(stmt, 3), sqlite3_column_bytes(stmt, 4)); - sqlite3_finalize(stmt); return -1; + " FROM channels WHERE channel_id=?", -1, &stmt, NULL); + if (rc == SQLITE_OK) rc = sqlite3_bind_text(stmt, 1, channel_id, -1, SQLITE_STATIC); + if (rc == SQLITE_OK) rc = sqlite3_step(stmt); + int result = TOPO_SQLITE_LOOKUP_ERROR; + if (rc == SQLITE_DONE) { result = TOPO_SQLITE_LOOKUP_MISSING; goto done; } + if (rc != SQLITE_ROW) goto done; + for (int col = 2; col <= 4; col++) { + if (!(col == 2 ? x25519_pub != NULL : col == 3 ? ed25519_pub != NULL : signature != NULL)) continue; + int size = sqlite3_column_bytes(stmt, col), expected = col == 4 ? 64 : 32; + if (size == expected) continue; + if (size == 0 && sqlite3_errcode(db) != SQLITE_NOMEM) result = TOPO_SQLITE_LOOKUP_MISSING; + else DEBUG_ERROR(DEBUG_CATEGORY_BGP, "channel lookup: invalid field channel=%s column=%d bytes=%d expected=%d", + channel_id, col, size, expected); + goto done; } if (name_out && name_sz > 0) { const unsigned char* txt = sqlite3_column_text(stmt, 0); @@ -897,8 +905,18 @@ int topo_node_sqlite_channel_get(sqlite3* db, const char* channel_id, if (x25519_pub) memcpy(x25519_pub, sqlite3_column_blob(stmt, 2), 32); if (ed25519_pub) memcpy(ed25519_pub, sqlite3_column_blob(stmt, 3), 32); if (signature) memcpy(signature, sqlite3_column_blob(stmt, 4), 64); - sqlite3_finalize(stmt); - return 0; + result = 0; +done: + { + int final_rc = sqlite3_finalize(stmt); + if (final_rc != SQLITE_OK) result = TOPO_SQLITE_LOOKUP_ERROR; + if (result == TOPO_SQLITE_LOOKUP_ERROR) + DEBUG_ERROR(DEBUG_CATEGORY_BGP, "channel lookup failed channel=%s rc=%d finalize=%d: %s", + channel_id, rc, final_rc, sqlite3_errmsg(db)); + else if (result == TOPO_SQLITE_LOOKUP_MISSING) + DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "channel lookup: dependency unavailable channel=%s", channel_id); + } + return result; } int topo_node_sqlite_channel_get_priv(sqlite3* db, const char* channel_id, @@ -977,23 +995,26 @@ int topo_node_sqlite_get_ed25519_pubkey(sqlite3* db, uint64_t node_id, uint8_t p { if (!db || !pubkey_out) { DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "get_ed25519_pubkey: invalid arguments node=%016llx", (unsigned long long)node_id); - return -1; + return TOPO_SQLITE_LOOKUP_ERROR; } sqlite3_stmt* stmt = NULL; int sql_rc = sqlite3_prepare_v2(db, "SELECT ed25519_pubkey FROM nodes WHERE node_id=?", -1, &stmt, NULL); if (sql_rc == SQLITE_OK) sql_rc = sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id); if (sql_rc == SQLITE_OK) sql_rc = sqlite3_step(stmt); - int rc = -1; + int rc = sql_rc == SQLITE_DONE ? TOPO_SQLITE_LOOKUP_MISSING : TOPO_SQLITE_LOOKUP_ERROR; + uint8_t key[32]; if (sql_rc == SQLITE_ROW) { const void* b = sqlite3_column_blob(stmt, 0); int bytes = sqlite3_column_bytes(stmt, 0); - if (b && bytes == 32) { memcpy(pubkey_out, b, 32); rc = 0; } + if (b && bytes == 32) { memcpy(key, b, 32); rc = 0; } + else if (bytes == 0 && sqlite3_errcode(db) != SQLITE_NOMEM) rc = TOPO_SQLITE_LOOKUP_MISSING; } int final_rc = sqlite3_finalize(stmt); - if (final_rc != SQLITE_OK) rc = -1; - if (rc && sql_rc == SQLITE_DONE && final_rc == SQLITE_OK) + if (final_rc != SQLITE_OK) rc = TOPO_SQLITE_LOOKUP_ERROR; + if (rc == 0) memcpy(pubkey_out, key, 32); + if (rc == TOPO_SQLITE_LOOKUP_MISSING) DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "get_ed25519_pubkey: unknown node=%016llx", (unsigned long long)node_id); - else if (rc) DEBUG_WARN(DEBUG_CATEGORY_ROUTING, "get_ed25519_pubkey: unavailable node=%016llx sql=%d finalize=%d: %s", + else if (rc) DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "get_ed25519_pubkey: unavailable node=%016llx sql=%d finalize=%d: %s", (unsigned long long)node_id, sql_rc, final_rc, sqlite3_errmsg(db)); return rc; } diff --git a/src/routing_layer/topo_node_sqlite.h b/src/routing_layer/topo_node_sqlite.h index 2b587dcc..dadb0834 100644 --- a/src/routing_layer/topo_node_sqlite.h +++ b/src/routing_layer/topo_node_sqlite.h @@ -17,6 +17,10 @@ #define PEERS_JOIN_TS_SIZE 8 #define PEERS_UPDATE_SIG_SIZE 64 +/* Результаты channel_get/get_ed25519_pubkey: отсутствие зависимости и отказ чтения различаются. */ +#define TOPO_SQLITE_LOOKUP_MISSING (-1) +#define TOPO_SQLITE_LOOKUP_ERROR (-2) + /* flags byte in wire format */ #define PEERS_FLAG_HAS_JOIN 0x01 @@ -104,7 +108,9 @@ int topo_node_sqlite_member_del(sqlite3* db, const char* channel_id, uint64_t no int topo_node_sqlite_node_update_verified(sqlite3* db, uint64_t node_id, const char* name, const uint8_t* x25519, const uint8_t* ed25519, uint64_t update_ts, time_t created_at); -/* Метаданные канала; 0/-1. Все выходы необязательны; name_sz включает NUL, ключи по 32, подпись 64 байта. */ +/* Метаданные канала: 0 — успех, LOOKUP_MISSING — нет строки/запрошенного ключа, + * LOOKUP_ERROR — аргументы/SQL/повреждённый размер. Выходы действительны только при 0. + * Все выходы необязательны; name_sz включает NUL, ключи по 32, подпись 64 байта. */ int topo_node_sqlite_channel_get(sqlite3* db, const char* channel_id, char* name_out, int name_sz, uint64_t* owner_node_id, uint8_t* x25519_pub, uint8_t* ed25519_pub, uint8_t* signature); @@ -126,7 +132,8 @@ int topo_node_sqlite_channel_set_privs(sqlite3* db, const char* channel_id, int topo_node_sqlite_node_set_online(sqlite3* db, uint64_t node_id, int online); /* online из nodes; 0, если записи нет или запрос не выполнен. */ int topo_node_sqlite_node_get_online(sqlite3* db, uint64_t node_id); -/* Скопировать ровно 32 байта Ed25519 из nodes: 0 — найден, -1 — отсутствует/другая длина/ошибка SQLite. +/* Скопировать ровно 32 байта Ed25519 из nodes: 0 — найден, LOOKUP_MISSING — нет строки/ключа, + * LOOKUP_ERROR — аргументы/SQL/повреждённый размер. При отказе выход не меняется. * Значение байтов не определяет наличие ключа; криптографическую пригодность проверяет операция verify. */ int topo_node_sqlite_get_ed25519_pubkey(sqlite3* db, uint64_t node_id, uint8_t pubkey_out[32]);