diff --git a/src/chat/chat_sync.c b/src/chat/chat_sync.c index 2ad30049..0a84ef02 100644 --- a/src/chat/chat_sync.c +++ b/src/chat/chat_sync.c @@ -95,19 +95,19 @@ static struct ETCP_CONN* cs_find_conn_for_node(struct UTUN_INSTANCE* inst, uint6 static int cs_send(struct chat_sync* cs, const char* ch_id, uint64_t dst, const uint8_t* payload, size_t len) { - if (len < 1) return -1; + if (len < 1) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: cs_send len<1", CS_ID); return -1; } uint8_t ch_len = (uint8_t)strlen(ch_id); - if (ch_len > 63) return -1; + if (ch_len > 63) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: cs_send ch_len=%u > 63", CS_ID, ch_len); return -1; } size_t total = 1 + 1 + ch_len + len; uint8_t* buf = u_malloc(total); - if (!buf) return -1; + if (!buf) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: cs_send alloc(%zu) failed", CS_ID, total); return -1; } uint8_t* p = buf; *p++ = ETCP_RT_ID_CHAT_SYNC; *p++ = ch_len; memcpy(p, ch_id, ch_len); p += ch_len; memcpy(p, payload, len); struct ll_entry* entry = queue_entry_new(0); - if (!entry) { u_free(buf); return -1; } + if (!entry) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: cs_send queue_entry_new failed", CS_ID); u_free(buf); return -1; } entry->dgram = buf; entry->len = total; DEBUG_INFO(DEBUG_CATEGORY_DB_SYNC, "%s: SEND %s to=%016llx ch=%s len=%zu", CS_ID, cs_msg_name(payload[0]), (unsigned long long)dst, ch_id, len); @@ -150,7 +150,10 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer, static void chat_sync_recv_cb(struct ETCP_CONN* conn, struct ll_entry* entry) { if (!entry || entry->len < 4) { - if (entry) { if (entry->dgram) u_free(entry->dgram); queue_entry_free(entry); } + if (entry) { + DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: recv short entry len=%zu conn=%s", CS_ID, entry->len, conn ? conn->log_name : "?"); + if (entry->dgram) u_free(entry->dgram); queue_entry_free(entry); + } return; } if (!g_cs || !g_cs->initialized) { u_free(entry->dgram); queue_entry_free(entry); return; } @@ -725,7 +728,7 @@ void chat_sync_connect_from_invite(uint64_t channel_id, uint64_t node_id, } struct chat_invite* inv = u_calloc(1, sizeof(struct chat_invite)); - if (!inv) return; + if (!inv) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: connect_from_invite calloc failed", CS_ID); return; } inv->channel_id = channel_id; inv->node_id = node_id; @@ -733,7 +736,7 @@ void chat_sync_connect_from_invite(uint64_t channel_id, uint64_t node_id, size_t addrs_sz = addrs_data_len > 0 ? (size_t)addrs_data_len : (size_t)addr_count * 9; inv->addrs_data = u_malloc(addrs_sz); - if (!inv->addrs_data) { u_free(inv); return; } + if (!inv->addrs_data) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: connect_from_invite malloc(%zu) failed", CS_ID, addrs_sz); u_free(inv); return; } memcpy(inv->addrs_data, addrs_data, addrs_sz); inv->addr_count = addr_count; @@ -765,7 +768,9 @@ void chat_sync_connect_from_invite(uint64_t channel_id, uint64_t node_id, /* ─── chat_sync_join_channel: join channel via already-connected peer ─── */ void chat_sync_join_channel(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t target_node_id) { - if (!g_cs || !inst || !ch_id || !ch_id[0]) return; + if (!g_cs) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: join_channel: g_cs=NULL, chat_sync not initialized", CS_ID); return; } + if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: join_channel: inst=NULL", CS_ID); return; } + if (!ch_id || !ch_id[0]) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: join_channel: ch_id NULL/empty", CS_ID); return; } uint64_t channel_id = strtoull(ch_id, NULL, 10); if (channel_id == 0) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: join_channel invalid ch_id='%s'", CS_ID, ch_id); return; } @@ -832,7 +837,7 @@ static int _get_node_name(sqlite3* db, uint64_t node_id, char* out, size_t sz) { if (!db || !out || !sz) return -1; sqlite3_stmt* st = NULL; sqlite3_prepare_v2(db, "SELECT name FROM nodes WHERE node_id=?", -1, &st, NULL); - if (!st) return -1; + if (!st) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: _get_node_name prepare failed node=0x%016llx", CS_ID, (unsigned long long)node_id); return -1; } sqlite3_bind_int64(st, 1, (sqlite3_int64)node_id); int rc = -1; if (sqlite3_step(st) == SQLITE_ROW) { @@ -956,7 +961,9 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer, uint8_t inv_flags = *p++; const uint8_t* inviter_join_sig = NULL; uint64_t inviter_join_ts = 0; if (inv_flags & PEERS_FLAG_HAS_JOIN) { - if (p + 72 > pl + len) return; inviter_join_sig = p; p += 64; memcpy(&inviter_join_ts, p, 8); p += 8; } + if (p + 72 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INFO_RESP truncated at inviter_join_sig peer=%016llx", CS_ID, (unsigned long long)peer); return; } + inviter_join_sig = p; p += 64; memcpy(&inviter_join_ts, p, 8); p += 8; + } const uint8_t* inviter_update_sig = p; p += 64; uint64_t inviter_update_ts; memcpy(&inviter_update_ts, p, 8); p += 8; uint8_t inv_userinfo_len = *p++; @@ -1157,7 +1164,7 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer, uint8_t sid = *p++; uint8_t proto = *p++; int ip_len = (fm == 4) ? 4 : 16; - if (p + ip_len + 2 > pl + len) break; + if (p + ip_len + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: JOIN addr truncated node=0x%016llx fm=%u i=%u", CS_ID, (unsigned long long)node_id, fm, i); break; } const uint8_t* ip = p; p += ip_len; uint16_t port = ((uint16_t)p[0] << 8) | p[1]; p += 2; @@ -1251,14 +1258,14 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer, uint16_t pc; memcpy(&pc, p, 2); p += 2; DEBUG_TRACE(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME ch=%s from=%016llx peers=%u", CS_ID, ch_id, (unsigned long long)peer, pc); for (uint16_t i = 0; i < pc; i++) { - if ((size_t)(p - pl) + 8 + 32 + 32 + 1 + 64 + 8 + 1 > len) break; /* min: id+x25519+ed+flags+update_sig(64+8)+nl+ac */ + if ((size_t)(p - pl) + 8 + 32 + 32 + 1 + 64 + 8 + 1 > len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME peer[%u] truncated at %td len=%zu", CS_ID, i, p - pl, len); break; } /* min: id+x25519+ed+flags+update_sig(64+8)+nl+ac */ uint64_t node_id; memcpy(&node_id, p, 8); p += 8; const uint8_t* x25519 = p; p += 32; const uint8_t* ed_pub = p; p += 32; uint8_t flags = *p++; const uint8_t* join_sig = NULL; uint64_t join_ts = 0; if (flags & PEERS_FLAG_HAS_JOIN) { - if (p + 64 + 8 > pl + len) break; + if (p + 64 + 8 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME join_sig truncated node=0x%016llx i=%u", CS_ID, (unsigned long long)node_id, i); break; } join_sig = p; p += 64; memcpy(&join_ts, p, 8); p += 8; } @@ -1313,28 +1320,27 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer, DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] WELCOME save addrs node=0x%016llx ac=%d", CS_ID, (unsigned long long)node_id, ac); for (uint8_t j = 0; j < ac; j++) { - if (p + 2 > pl + len) break; + if (p + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME addr[%u] header truncated node=0x%016llx", CS_ID, j, (unsigned long long)node_id); break; } uint8_t fm = *p++; uint8_t sid = *p++; uint8_t proto = *p++; int ip_len = (fm == 4) ? 4 : 16; - if (p + ip_len + 2 > pl + len) break; + if (p + ip_len + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: WELCOME addr[%u] ip truncated node=0x%016llx fm=%u", CS_ID, j, (unsigned long long)node_id, fm); break; } const uint8_t* ip = p; p += ip_len; uint16_t port = ((uint16_t)p[0] << 8) | p[1]; p += 2; char sql[256]; snprintf(sql, sizeof(sql), "INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)" " VALUES(?,?,?,?,?,0,?)"); - sqlite3_stmt* stmt = NULL; - if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) { - sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id); - sqlite3_bind_int(stmt, 2, fm); - sqlite3_bind_int(stmt, 3, (int)proto); - sqlite3_bind_blob(stmt, 4, ip, ip_len, SQLITE_STATIC); - sqlite3_bind_int(stmt, 5, (int)port); - sqlite3_bind_int(stmt, 6, (int)sid); - sqlite3_step(stmt); sqlite3_finalize(stmt); - } + sqlite3_stmt* stmt2 = NULL; + if (sqlite3_prepare_v2(db, sql, -1, &stmt2, NULL) == SQLITE_OK) { + sqlite3_bind_int64(stmt2, 1, (sqlite3_int64)node_id); + sqlite3_bind_int(stmt2, 2, fm); + sqlite3_bind_blob(stmt2, 3, ip, ip_len, SQLITE_STATIC); + sqlite3_bind_int(stmt2, 4, (int)port); + sqlite3_bind_int(stmt2, 5, (int)sid); + sqlite3_step(stmt2); sqlite3_finalize(stmt2); + } if (fm == 4) DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] WELCOME INSERT node=0x%016llx sock=%d %d.%d.%d.%d:%d", CS_ID, (unsigned long long)node_id, sid, ip[0], ip[1], ip[2], ip[3], port); @@ -1427,12 +1433,12 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer, DEBUG_INFO(DEBUG_CATEGORY_DEBUG, "%s: [ADDR_SYNC] PEER_UPSERT save addrs node=0x%016llx ac=%d", CS_ID, (unsigned long long)node_id, ac); for (uint8_t i = 0; i < ac; i++) { - if (p + 2 > pl + len) break; + if (p + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: PEER_UPSERT addr[%u] header truncated node=0x%016llx", CS_ID, i, (unsigned long long)node_id); break; } uint8_t fm = *p++; uint8_t sid = *p++; uint8_t proto = *p++; int ip_len = (fm == 4) ? 4 : 16; - if (p + ip_len + 2 > pl + len) break; + if (p + ip_len + 2 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: PEER_UPSERT addr[%u] ip truncated node=0x%016llx fm=%u", CS_ID, i, (unsigned long long)node_id, fm); break; } const uint8_t* ip = p; p += ip_len; uint16_t port = ((uint16_t)p[0] << 8) | p[1]; p += 2; @@ -1509,7 +1515,8 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer, uint8_t inv_flags = *p++; const uint8_t* inviter_join_sig = NULL; uint64_t inviter_join_ts = 0; if (inv_flags & PEERS_FLAG_HAS_JOIN) { - if (p + 72 > pl + len) return; inviter_join_sig = p; p += 64; memcpy(&inviter_join_ts, p, 8); p += 8; } + if (p + 72 > pl + len) { DEBUG_WARN(DEBUG_CATEGORY_DB_SYNC, "%s: CHANNEL_INVITE truncated at join_sig/ts from=%016llx", CS_ID, (unsigned long long)peer); return; } + inviter_join_sig = p; p += 64; memcpy(&inviter_join_ts, p, 8); p += 8; } /* skip inviter_update_sig/ts/userinfo for now — verify channel sig only */ p += 64; uint64_t inviter_update_ts; memcpy(&inviter_update_ts, p, 8); p += 8; uint8_t userinfo_len = *p++; p += userinfo_len; @@ -1583,8 +1590,11 @@ static void cs_handle_channel_invite(struct chat_sync* cs, uint64_t peer, /* ─── chat_sync_invite_to_channel: пригласить узел в наш канал ─── */ void chat_sync_invite_to_channel(struct UTUN_INSTANCE* inst, const char* ch_id, uint64_t target_node_id) { - if (!g_cs || !inst || !ch_id || !ch_id[0]) return; - if (target_node_id == 0 || target_node_id == inst->node_id) return; + if (!g_cs) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: g_cs=NULL, chat_sync not initialized", CS_ID); return; } + if (!inst) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: inst=NULL", CS_ID); return; } + if (!ch_id || !ch_id[0]) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: ch_id NULL/empty", CS_ID); return; } + if (target_node_id == 0) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: target_node_id=0", CS_ID); return; } + if (target_node_id == inst->node_id) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel: self-invite rejected self=0x%016llx", CS_ID, (unsigned long long)inst->node_id); return; } uint64_t channel_id = strtoull(ch_id, NULL, 10); if (channel_id == 0) { DEBUG_ERROR(DEBUG_CATEGORY_DB_SYNC, "%s: invite_to_channel invalid ch_id='%s'", CS_ID, ch_id); return; } diff --git a/tools/chatgui/src/invitedialog.cpp b/tools/chatgui/src/invitedialog.cpp index 71d36de5..a4ba6774 100644 --- a/tools/chatgui/src/invitedialog.cpp +++ b/tools/chatgui/src/invitedialog.cpp @@ -151,6 +151,39 @@ void InviteDialog::onSendInvite() { } uint64_t targetNodeId = sc_derive_node_id_from_pubkey((const uint8_t*)d.pubkey.constData()); + + /* diagnostic: show decoded link info */ + { + uint64_t myNodeId = m_node ? m_node->nodeIdHex().toULongLong(nullptr, 16) : 0; + QString pkHex = QString::fromLatin1(d.pubkey.toHex()); + QString pkShort = pkHex.left(8) + ".." + pkHex.right(4); + QString addrInfo; + for (int i = 0; i < d.addrs.size() && i < 3; i++) { + if (i > 0) addrInfo += ", "; + uint32_t ip4 = 0; + if (d.addrs[i].family == 4 && d.addrs[i].address.size() >= 4) { + memcpy(&ip4, d.addrs[i].address.constData(), 4); + addrInfo += QString("%1.%2.%3.%4:%5") + .arg((ip4>>24)&0xFF).arg((ip4>>16)&0xFF).arg((ip4>>8)&0xFF).arg(ip4&0xFF) + .arg(d.addrs[i].port); + } else { + addrInfo += QString("v%1:%2").arg(d.addrs[i].family).arg(d.addrs[i].port); + } + } + if (d.addrs.size() > 3) addrInfo += QString(" +%1 more").arg(d.addrs.size() - 3); + QString diag = QString("Ссылка: узел 0x%1 ключ %2, %3 адр. (%4)") + .arg(targetNodeId, 16, 16, QChar('0')) + .arg(pkShort) + .arg(d.addrs.size()) + .arg(addrInfo); + GUI_INFO("invite_by_link: %s", diag.toUtf8().constData()); + if (myNodeId != 0 && myNodeId == targetNodeId) { + GUI_WARN("invite_by_link: self-invite rejected — link contains own pubkey, node=0x%016llx", (unsigned long long)myNodeId); + setInviteStatus("Ошибка: это ваша собственная ссылка (нельзя пригласить себя)", true); + return; + } + setInviteStatus(diag); + } m_inviteSending = true; m_inviteTargetNodeId = targetNodeId; m_inviteSendBtn->setEnabled(false);