Propagate failures when storing verified node identities
This commit is contained in:
1 parent
324b289968
commit
14c5ddf864
2 files changed
+53
-11
No files matched your search
@@ -724,11 +724,16 @@ int topo_node_sqlite_member_owner_put(sqlite3* db, const char* channel_id, uint6
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Записывает уже проверенную вызывающим идентичность; любой отказ SQL возвращается вызывающему. */
|
||||
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) {
|
||||
if (!db || !x25519 || !ed25519) return -1;
|
||||
if (!db || !x25519 || !ed25519) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "verified node write: invalid arguments node=%016llx", (unsigned long long)node_id);
|
||||
return -1;
|
||||
}
|
||||
sqlite3_stmt* stmt = NULL;
|
||||
if (sqlite3_prepare_v2(db,
|
||||
const char* stage = "prepare";
|
||||
int rc = sqlite3_prepare_v2(db,
|
||||
"INSERT INTO nodes(node_id, name, x25519_pubkey, ed25519_pubkey, created_at, update_ts, online)"
|
||||
" VALUES(?,?,?,?,?,?,1)"
|
||||
" ON CONFLICT(node_id) DO UPDATE SET"
|
||||
@@ -739,15 +744,25 @@ int topo_node_sqlite_node_update_verified(sqlite3* db, uint64_t node_id,
|
||||
" created_at=COALESCE(nodes.created_at, excluded.created_at),"
|
||||
" update_ts=CASE WHEN nodes.update_ts IS NULL OR excluded.update_ts > nodes.update_ts"
|
||||
" THEN excluded.update_ts ELSE nodes.update_ts END",
|
||||
-1, &stmt, NULL) != SQLITE_OK) return -1;
|
||||
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id);
|
||||
sqlite3_bind_text(stmt, 2, name && name[0] ? name : "", -1, SQLITE_STATIC);
|
||||
sqlite3_bind_blob(stmt, 3, x25519, 32, SQLITE_STATIC);
|
||||
sqlite3_bind_blob(stmt, 4, ed25519, 32, SQLITE_STATIC);
|
||||
sqlite3_bind_int64(stmt, 5, (sqlite3_int64)created_at);
|
||||
sqlite3_bind_int64(stmt, 6, (sqlite3_int64)update_ts);
|
||||
sqlite3_step(stmt);
|
||||
sqlite3_finalize(stmt);
|
||||
-1, &stmt, NULL);
|
||||
if (rc == SQLITE_OK) {
|
||||
stage = "bind";
|
||||
rc = sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_text(stmt, 2, name && name[0] ? name : "", -1, SQLITE_STATIC);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_blob(stmt, 3, x25519, 32, SQLITE_STATIC);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_blob(stmt, 4, ed25519, 32, SQLITE_STATIC);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_int64(stmt, 5, (sqlite3_int64)created_at);
|
||||
if (rc == SQLITE_OK) rc = sqlite3_bind_int64(stmt, 6, (sqlite3_int64)update_ts);
|
||||
}
|
||||
if (rc == SQLITE_OK) { stage = "step"; rc = sqlite3_step(stmt); }
|
||||
if (rc != SQLITE_DONE) DEBUG_ERROR(DEBUG_CATEGORY_BGP, "verified node write: node=%016llx stage=%s rc=%d: %s",
|
||||
(unsigned long long)node_id, stage, rc, sqlite3_errmsg(db));
|
||||
int final_rc = sqlite3_finalize(stmt);
|
||||
if (final_rc != SQLITE_OK && rc == SQLITE_DONE) DEBUG_ERROR(DEBUG_CATEGORY_BGP,
|
||||
"verified node write: node=%016llx stage=finalize rc=%d: %s", (unsigned long long)node_id, final_rc, sqlite3_errmsg(db));
|
||||
if (rc != SQLITE_DONE || final_rc != SQLITE_OK) return -1;
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_BGP, "verified node stored: node=%016llx timestamp=%llu changed=%d",
|
||||
(unsigned long long)node_id, (unsigned long long)update_ts, sqlite3_changes(db));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,32 @@ static void test_zero_port_schema(void) {
|
||||
}
|
||||
|
||||
/* Новый wire и SQL сохраняют адреса, протоколы, классификацию и REALITY; смена формата оставляет bootstrap. */
|
||||
/* Отказ INSERT/UPDATE не должен выглядеть успешным сохранением уже проверенного узла. */
|
||||
static void test_verified_write(void) {
|
||||
sqlite3* db = NULL; uint8_t key[32] = {1};
|
||||
assert(sqlite3_open(":memory:", &db) == SQLITE_OK && !topo_node_sqlite_init(db));
|
||||
assert(!topo_node_sqlite_node_update_verified(db, 7, "before", key, key, 100, 1));
|
||||
assert(sqlite3_exec(db, "CREATE TRIGGER reject_node BEFORE INSERT ON nodes "
|
||||
"BEGIN SELECT RAISE(ABORT,'test insert rejection'); END", NULL, NULL, NULL) == SQLITE_OK);
|
||||
assert(topo_node_sqlite_node_update_verified(db, 8, "rejected", key, key, 101, 1) < 0);
|
||||
assert(sqlite3_exec(db, "DROP TRIGGER reject_node; CREATE TRIGGER reject_node BEFORE UPDATE ON nodes "
|
||||
"BEGIN SELECT RAISE(ABORT,'test update rejection'); END", NULL, NULL, NULL) == SQLITE_OK);
|
||||
assert(topo_node_sqlite_node_update_verified(db, 7, "rejected", key, key, 101, 1) < 0);
|
||||
sqlite3_stmt* st = NULL;
|
||||
assert(sqlite3_prepare_v2(db, "SELECT name,update_ts FROM nodes ORDER BY node_id", -1, &st, NULL) == SQLITE_OK);
|
||||
assert(sqlite3_step(st) == SQLITE_ROW && !strcmp((const char*)sqlite3_column_text(st, 0), "before"));
|
||||
assert(sqlite3_column_int64(st, 1) == 100 && sqlite3_step(st) == SQLITE_DONE); sqlite3_finalize(st);
|
||||
assert(sqlite3_exec(db, "DROP TRIGGER reject_node", NULL, NULL, NULL) == SQLITE_OK);
|
||||
assert(!topo_node_sqlite_node_update_verified(db, 7, "after", key, key, 101, 1));
|
||||
assert(sqlite3_prepare_v2(db, "SELECT name,update_ts FROM nodes WHERE node_id=7", -1, &st, NULL) == SQLITE_OK);
|
||||
assert(sqlite3_step(st) == SQLITE_ROW && !strcmp((const char*)sqlite3_column_text(st, 0), "after"));
|
||||
assert(sqlite3_column_int64(st, 1) == 101); sqlite3_finalize(st);
|
||||
assert(sqlite3_exec(db, "DROP TABLE nodes", NULL, NULL, NULL) == SQLITE_OK);
|
||||
assert(topo_node_sqlite_node_update_verified(db, 7, "no table", key, key, 102, 1) < 0);
|
||||
sqlite3_close(db);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_BGP, "[PASS] verified node writes: insert/update, rejected writes, prepare failure and stored state");
|
||||
}
|
||||
|
||||
static void test_compact_addresses(struct UTUN_INSTANCE *inst) {
|
||||
test_zero_port_schema();
|
||||
sqlite3 *saved_db = inst->topo_sqlite_db;
|
||||
@@ -239,6 +265,7 @@ int main(void) {
|
||||
inst.node_id = sc_derive_node_id_from_pubkey(inst.my_keys.public_key);
|
||||
assert(sqlite3_open(":memory:", &inst.topo_sqlite_db) == SQLITE_OK);
|
||||
assert(topo_node_sqlite_init(inst.topo_sqlite_db) == 0);
|
||||
test_verified_write();
|
||||
test_compact_addresses(&inst);
|
||||
|
||||
struct TOPO_NODE* first = record(&inst, 100, "old", 1);
|
||||
|
||||
Reference in new issue
Block a user