|
|
|
@ -86,6 +86,21 @@ static void smeta6_lookup(struct TOPO_SOCKMETA6* head, uint8_t sid, uint8_t* cfg |
|
|
|
if (m->id == sid) { *cfg = m->config_type; *nat = m->nat_type; return; } |
|
|
|
if (m->id == sid) { *cfg = m->config_type; *nat = m->nat_type; return; } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* reality-параметры сокета → фиксированный blob для node_addresses.options.
|
|
|
|
|
|
|
|
Возвращает 1 и заполняет opts, если у сокета есть reality; иначе 0. */ |
|
|
|
|
|
|
|
static int reality_opts_build(struct TOPO_NODE* ni, uint8_t sid, struct TOPO_ADDR_REALITY_OPTS* opts) { |
|
|
|
|
|
|
|
if (!ni || !opts) return 0; |
|
|
|
|
|
|
|
for (const struct TOPO_REALITY_SOCK* r = ni->reality_socks; r; r = r->next) { |
|
|
|
|
|
|
|
if (r->socket_id != sid) continue; |
|
|
|
|
|
|
|
memcpy(opts->short_id, r->short_id, 8); |
|
|
|
|
|
|
|
memcpy(opts->server_pubkey, r->server_pubkey, 32); |
|
|
|
|
|
|
|
memcpy(opts->version, r->version, 3); |
|
|
|
|
|
|
|
memcpy(opts->server_name, r->server_name, TOPO_REALITY_SNAME_MAX); |
|
|
|
|
|
|
|
return 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* ── Персистенция адресов узла (источник истины — BGP/topo_group) ── */ |
|
|
|
/* ── Персистенция адресов узла (источник истины — BGP/topo_group) ── */ |
|
|
|
|
|
|
|
|
|
|
|
int topo_node_sqlite_addrs_put(sqlite3* db, uint64_t node_id, struct TOPO_NODE* ni) { |
|
|
|
int topo_node_sqlite_addrs_put(sqlite3* db, uint64_t node_id, struct TOPO_NODE* ni) { |
|
|
|
@ -109,17 +124,19 @@ int topo_node_sqlite_addrs_put(sqlite3* db, uint64_t node_id, struct TOPO_NODE* |
|
|
|
|
|
|
|
|
|
|
|
sqlite3_stmt* is = NULL; |
|
|
|
sqlite3_stmt* is = NULL; |
|
|
|
if (sqlite3_prepare_v2(db, |
|
|
|
if (sqlite3_prepare_v2(db, |
|
|
|
"INSERT INTO node_addresses(node_id,family,protocol,address,port,addr_type,config_type,nat_type,socket_id)" |
|
|
|
"INSERT INTO node_addresses(node_id,family,protocol,address,port,addr_type,config_type,nat_type,socket_id,options)" |
|
|
|
" VALUES(?,?,?,?,?,?,?,?,?)", -1, &is, NULL) != SQLITE_OK) { |
|
|
|
" VALUES(?,?,?,?,?,?,?,?,?,?)", -1, &is, NULL) != SQLITE_OK) { |
|
|
|
sqlite3_exec(db, "COMMIT", NULL, NULL, NULL); |
|
|
|
sqlite3_exec(db, "COMMIT", NULL, NULL, NULL); |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
int written = 0; |
|
|
|
int written = 0; |
|
|
|
|
|
|
|
struct TOPO_ADDR_REALITY_OPTS ropts; |
|
|
|
for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) { |
|
|
|
for (const struct TOPO_ADDR4* a = ni->v4_addrs; a; a = a->next) { |
|
|
|
uint8_t cfg, nat; smeta4_lookup(ni->v4_sock_meta, a->socket_id, &cfg, &nat); |
|
|
|
uint8_t cfg, nat; smeta4_lookup(ni->v4_sock_meta, a->socket_id, &cfg, &nat); |
|
|
|
int at = (a->type == TOPO_ADDR_INTERFACE) ? addr_type_from_ip(4, a->addr) |
|
|
|
int at = (a->type == TOPO_ADDR_INTERFACE) ? addr_type_from_ip(4, a->addr) |
|
|
|
: addr_type_classify(cfg, nat); |
|
|
|
: addr_type_classify(cfg, nat); |
|
|
|
|
|
|
|
int has_reality = (a->protocol & TOPO_PROTO_REALITY) && reality_opts_build(ni, a->socket_id, &ropts); |
|
|
|
sqlite3_bind_int64(is, 1, (sqlite3_int64)node_id); |
|
|
|
sqlite3_bind_int64(is, 1, (sqlite3_int64)node_id); |
|
|
|
sqlite3_bind_int(is, 2, 4); |
|
|
|
sqlite3_bind_int(is, 2, 4); |
|
|
|
sqlite3_bind_int(is, 3, (int)a->protocol); |
|
|
|
sqlite3_bind_int(is, 3, (int)a->protocol); |
|
|
|
@ -129,6 +146,8 @@ int topo_node_sqlite_addrs_put(sqlite3* db, uint64_t node_id, struct TOPO_NODE* |
|
|
|
sqlite3_bind_int(is, 7, (int)cfg); |
|
|
|
sqlite3_bind_int(is, 7, (int)cfg); |
|
|
|
sqlite3_bind_int(is, 8, (int)nat); |
|
|
|
sqlite3_bind_int(is, 8, (int)nat); |
|
|
|
sqlite3_bind_int(is, 9, (int)a->socket_id); |
|
|
|
sqlite3_bind_int(is, 9, (int)a->socket_id); |
|
|
|
|
|
|
|
if (has_reality) sqlite3_bind_blob(is, 10, &ropts, sizeof(ropts), SQLITE_STATIC); |
|
|
|
|
|
|
|
else sqlite3_bind_null(is, 10); |
|
|
|
if (sqlite3_step(is) != SQLITE_DONE) |
|
|
|
if (sqlite3_step(is) != SQLITE_DONE) |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "addrs_put: INSERT failed node=%016llx fam=4 sock=%d at=%d cfg=%d nat=%d addr=%d.%d.%d.%d:%d: %s", |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "addrs_put: INSERT failed node=%016llx fam=4 sock=%d at=%d cfg=%d nat=%d addr=%d.%d.%d.%d:%d: %s", |
|
|
|
(unsigned long long)node_id, a->socket_id, at, cfg, nat, |
|
|
|
(unsigned long long)node_id, a->socket_id, at, cfg, nat, |
|
|
|
@ -140,6 +159,7 @@ int topo_node_sqlite_addrs_put(sqlite3* db, uint64_t node_id, struct TOPO_NODE* |
|
|
|
uint8_t cfg, nat; smeta6_lookup(ni->v6_sock_meta, a->socket_id, &cfg, &nat); |
|
|
|
uint8_t cfg, nat; smeta6_lookup(ni->v6_sock_meta, a->socket_id, &cfg, &nat); |
|
|
|
int at = (a->type == TOPO_ADDR_INTERFACE) ? ADDR_TYPE_NETIF |
|
|
|
int at = (a->type == TOPO_ADDR_INTERFACE) ? ADDR_TYPE_NETIF |
|
|
|
: addr_type_classify(cfg, nat); |
|
|
|
: addr_type_classify(cfg, nat); |
|
|
|
|
|
|
|
int has_reality = (a->protocol & TOPO_PROTO_REALITY) && reality_opts_build(ni, a->socket_id, &ropts); |
|
|
|
sqlite3_bind_int64(is, 1, (sqlite3_int64)node_id); |
|
|
|
sqlite3_bind_int64(is, 1, (sqlite3_int64)node_id); |
|
|
|
sqlite3_bind_int(is, 2, 6); |
|
|
|
sqlite3_bind_int(is, 2, 6); |
|
|
|
sqlite3_bind_int(is, 3, (int)a->protocol); |
|
|
|
sqlite3_bind_int(is, 3, (int)a->protocol); |
|
|
|
@ -149,6 +169,8 @@ int topo_node_sqlite_addrs_put(sqlite3* db, uint64_t node_id, struct TOPO_NODE* |
|
|
|
sqlite3_bind_int(is, 7, (int)cfg); |
|
|
|
sqlite3_bind_int(is, 7, (int)cfg); |
|
|
|
sqlite3_bind_int(is, 8, (int)nat); |
|
|
|
sqlite3_bind_int(is, 8, (int)nat); |
|
|
|
sqlite3_bind_int(is, 9, (int)a->socket_id); |
|
|
|
sqlite3_bind_int(is, 9, (int)a->socket_id); |
|
|
|
|
|
|
|
if (has_reality) sqlite3_bind_blob(is, 10, &ropts, sizeof(ropts), SQLITE_STATIC); |
|
|
|
|
|
|
|
else sqlite3_bind_null(is, 10); |
|
|
|
if (sqlite3_step(is) != SQLITE_DONE) |
|
|
|
if (sqlite3_step(is) != SQLITE_DONE) |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "addrs_put: INSERT failed node=%016llx fam=6 sock=%d at=%d cfg=%d nat=%d: %s", |
|
|
|
DEBUG_ERROR(DEBUG_CATEGORY_BGP, "addrs_put: INSERT failed node=%016llx fam=6 sock=%d at=%d cfg=%d nat=%d: %s", |
|
|
|
(unsigned long long)node_id, a->socket_id, at, cfg, nat, sqlite3_errmsg(db)); |
|
|
|
(unsigned long long)node_id, a->socket_id, at, cfg, nat, sqlite3_errmsg(db)); |
|
|
|
@ -255,6 +277,7 @@ int topo_node_sqlite_init(sqlite3* db) { |
|
|
|
" config_type INTEGER DEFAULT 0," |
|
|
|
" config_type INTEGER DEFAULT 0," |
|
|
|
" nat_type INTEGER DEFAULT 0," |
|
|
|
" nat_type INTEGER DEFAULT 0," |
|
|
|
" socket_id INTEGER NOT NULL DEFAULT 0," |
|
|
|
" socket_id INTEGER NOT NULL DEFAULT 0," |
|
|
|
|
|
|
|
" options BLOB," // reality-параметры (TOPO_ADDR_REALITY_OPTS)
|
|
|
|
" created_at INTEGER DEFAULT (unixepoch())" |
|
|
|
" created_at INTEGER DEFAULT (unixepoch())" |
|
|
|
");" |
|
|
|
");" |
|
|
|
"CREATE INDEX IF NOT EXISTS idx_na_node ON node_addresses(node_id);" |
|
|
|
"CREATE INDEX IF NOT EXISTS idx_na_node ON node_addresses(node_id);" |
|
|
|
@ -284,6 +307,29 @@ int topo_node_sqlite_init(sqlite3* db) { |
|
|
|
return -1; |
|
|
|
return -1; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* migration: добавить колонку options в уже существующую node_addresses (idempotent) */ |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
sqlite3_stmt* cs = NULL; |
|
|
|
|
|
|
|
int has_options = 0; |
|
|
|
|
|
|
|
if (sqlite3_prepare_v2(db, "PRAGMA table_info(node_addresses)", -1, &cs, NULL) == SQLITE_OK) { |
|
|
|
|
|
|
|
while (sqlite3_step(cs) == SQLITE_ROW) { |
|
|
|
|
|
|
|
const char* cn = (const char*)sqlite3_column_text(cs, 1); |
|
|
|
|
|
|
|
if (cn && strcmp(cn, "options") == 0) { has_options = 1; break; } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
sqlite3_finalize(cs); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if (!has_options) { |
|
|
|
|
|
|
|
char* aerr = NULL; |
|
|
|
|
|
|
|
int arc = sqlite3_exec(db, "ALTER TABLE node_addresses ADD COLUMN options BLOB", NULL, NULL, &aerr); |
|
|
|
|
|
|
|
if (arc != SQLITE_OK) { |
|
|
|
|
|
|
|
DEBUG_WARN(DEBUG_CATEGORY_BGP, "topo_node_sqlite_init: ALTER TABLE ADD options failed: %s", aerr ? aerr : "?"); |
|
|
|
|
|
|
|
if (aerr) sqlite3_free(aerr); |
|
|
|
|
|
|
|
} else { |
|
|
|
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "topo_node_sqlite_init: migrated node_addresses (added options column)"); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* backfill: вывести deleted из adm_tags (idempotent, самовосстановление) */ |
|
|
|
/* backfill: вывести deleted из adm_tags (idempotent, самовосстановление) */ |
|
|
|
{ |
|
|
|
{ |
|
|
|
sqlite3_stmt* s = NULL; |
|
|
|
sqlite3_stmt* s = NULL; |
|
|
|
@ -945,11 +991,12 @@ struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* gr |
|
|
|
|
|
|
|
|
|
|
|
struct TOPO_ADDR4* v4_head = NULL; struct TOPO_ADDR4* v4_tail = NULL; |
|
|
|
struct TOPO_ADDR4* v4_head = NULL; struct TOPO_ADDR4* v4_tail = NULL; |
|
|
|
struct TOPO_SOCKMETA4* m4_head = NULL; struct TOPO_SOCKMETA4* m4_tail = NULL; |
|
|
|
struct TOPO_SOCKMETA4* m4_head = NULL; struct TOPO_SOCKMETA4* m4_tail = NULL; |
|
|
|
|
|
|
|
struct TOPO_REALITY_SOCK* r_head = NULL; struct TOPO_REALITY_SOCK* r_tail = NULL; |
|
|
|
uint8_t sock_id_counter = 0; |
|
|
|
uint8_t sock_id_counter = 0; |
|
|
|
{ |
|
|
|
{ |
|
|
|
sqlite3_stmt* s = NULL; |
|
|
|
sqlite3_stmt* s = NULL; |
|
|
|
if (sqlite3_prepare_v2(db, |
|
|
|
if (sqlite3_prepare_v2(db, |
|
|
|
"SELECT address,port,addr_type,socket_id,protocol,config_type,nat_type FROM node_addresses" |
|
|
|
"SELECT address,port,addr_type,socket_id,protocol,config_type,nat_type,options FROM node_addresses" |
|
|
|
" WHERE node_id=? AND family=4 ORDER BY addr_type", |
|
|
|
" WHERE node_id=? AND family=4 ORDER BY addr_type", |
|
|
|
-1, &s, NULL) == SQLITE_OK) { |
|
|
|
-1, &s, NULL) == SQLITE_OK) { |
|
|
|
sqlite3_bind_int64(s, 1, (sqlite3_int64)node_id); |
|
|
|
sqlite3_bind_int64(s, 1, (sqlite3_int64)node_id); |
|
|
|
@ -983,6 +1030,22 @@ struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* gr |
|
|
|
else { m4_tail->next = m4; m4_tail = m4; } |
|
|
|
else { m4_tail->next = m4; m4_tail = m4; } |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (sqlite3_column_type(s, 7) == SQLITE_BLOB |
|
|
|
|
|
|
|
&& sqlite3_column_bytes(s, 7) == TOPO_ADDR_REALITY_OPTS_SIZE |
|
|
|
|
|
|
|
&& (proto & TOPO_PROTO_REALITY)) { |
|
|
|
|
|
|
|
const struct TOPO_ADDR_REALITY_OPTS* o = (const struct TOPO_ADDR_REALITY_OPTS*)sqlite3_column_blob(s, 7); |
|
|
|
|
|
|
|
struct TOPO_REALITY_SOCK* r = u_calloc(1, sizeof(*r)); |
|
|
|
|
|
|
|
if (r) { |
|
|
|
|
|
|
|
r->socket_id = sock_id; |
|
|
|
|
|
|
|
memcpy(r->short_id, o->short_id, 8); |
|
|
|
|
|
|
|
memcpy(r->server_pubkey, o->server_pubkey, 32); |
|
|
|
|
|
|
|
memcpy(r->version, o->version, 3); |
|
|
|
|
|
|
|
memcpy(r->server_name, o->server_name, TOPO_REALITY_SNAME_MAX); |
|
|
|
|
|
|
|
r->server_name[TOPO_REALITY_SNAME_MAX - 1] = 0; |
|
|
|
|
|
|
|
if (!r_head) r_head = r_tail = r; |
|
|
|
|
|
|
|
else { r_tail->next = r; r_tail = r; } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
sqlite3_finalize(s); |
|
|
|
sqlite3_finalize(s); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -993,7 +1056,7 @@ struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* gr |
|
|
|
{ |
|
|
|
{ |
|
|
|
sqlite3_stmt* s = NULL; |
|
|
|
sqlite3_stmt* s = NULL; |
|
|
|
if (sqlite3_prepare_v2(db, |
|
|
|
if (sqlite3_prepare_v2(db, |
|
|
|
"SELECT address,port,addr_type,socket_id,protocol,config_type,nat_type FROM node_addresses" |
|
|
|
"SELECT address,port,addr_type,socket_id,protocol,config_type,nat_type,options FROM node_addresses" |
|
|
|
" WHERE node_id=? AND family=6 ORDER BY addr_type", |
|
|
|
" WHERE node_id=? AND family=6 ORDER BY addr_type", |
|
|
|
-1, &s, NULL) == SQLITE_OK) { |
|
|
|
-1, &s, NULL) == SQLITE_OK) { |
|
|
|
sqlite3_bind_int64(s, 1, (sqlite3_int64)node_id); |
|
|
|
sqlite3_bind_int64(s, 1, (sqlite3_int64)node_id); |
|
|
|
@ -1027,6 +1090,22 @@ struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* gr |
|
|
|
else { m6_tail->next = m6; m6_tail = m6; } |
|
|
|
else { m6_tail->next = m6; m6_tail = m6; } |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (sqlite3_column_type(s, 7) == SQLITE_BLOB |
|
|
|
|
|
|
|
&& sqlite3_column_bytes(s, 7) == TOPO_ADDR_REALITY_OPTS_SIZE |
|
|
|
|
|
|
|
&& (proto6 & TOPO_PROTO_REALITY)) { |
|
|
|
|
|
|
|
const struct TOPO_ADDR_REALITY_OPTS* o = (const struct TOPO_ADDR_REALITY_OPTS*)sqlite3_column_blob(s, 7); |
|
|
|
|
|
|
|
struct TOPO_REALITY_SOCK* r = u_calloc(1, sizeof(*r)); |
|
|
|
|
|
|
|
if (r) { |
|
|
|
|
|
|
|
r->socket_id = sock_id; |
|
|
|
|
|
|
|
memcpy(r->short_id, o->short_id, 8); |
|
|
|
|
|
|
|
memcpy(r->server_pubkey, o->server_pubkey, 32); |
|
|
|
|
|
|
|
memcpy(r->version, o->version, 3); |
|
|
|
|
|
|
|
memcpy(r->server_name, o->server_name, TOPO_REALITY_SNAME_MAX); |
|
|
|
|
|
|
|
r->server_name[TOPO_REALITY_SNAME_MAX - 1] = 0; |
|
|
|
|
|
|
|
if (!r_head) r_head = r_tail = r; |
|
|
|
|
|
|
|
else { r_tail->next = r; r_tail = r; } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
sqlite3_finalize(s); |
|
|
|
sqlite3_finalize(s); |
|
|
|
} |
|
|
|
} |
|
|
|
@ -1043,6 +1122,7 @@ struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* gr |
|
|
|
ni->v6_addrs = v6_head; |
|
|
|
ni->v6_addrs = v6_head; |
|
|
|
ni->v4_sock_meta = m4_head; |
|
|
|
ni->v4_sock_meta = m4_head; |
|
|
|
ni->v6_sock_meta = m6_head; |
|
|
|
ni->v6_sock_meta = m6_head; |
|
|
|
|
|
|
|
ni->reality_socks = r_head; |
|
|
|
|
|
|
|
|
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "node_load: node 0x%016llx loaded from DB name=%s v4=%d v6=%d", |
|
|
|
DEBUG_INFO(DEBUG_CATEGORY_BGP, "node_load: node 0x%016llx loaded from DB name=%s v4=%d v6=%d", |
|
|
|
(unsigned long long)node_id, name ? name : "", |
|
|
|
(unsigned long long)node_id, name ? name : "", |
|
|
|
|