Browse Source

fix: UDP packet size and addr_type classification

- etcp_connections.h: add WIRE_OVERHEAD, IP_UDP_OVERHEAD_V4/V6, SC_ENCRYPT_OVERHEAD
  (properly accounts for v6 IP(40)+UDP(8)+SC(3)+CCM tag(16) = 67 vs old UDP_HDR_SIZE=28)
- etcp_connections.c etcp_encrypt_send: use WIRE_OVERHEAD instead of UDP_HDR_SIZE
- etcp_connections.c send_init_response: clamp padding to max_data = mtu - WIRE_OVERHEAD
- chat_core_priv.h: add addr_type_from_ip() classifier
- chat_profile.c, chat_sync.c, member_sync.c: use classified addr_type instead of hardcoded 0
- chat_sync.c: skip zero nat_addr in JOIN, fall back to interface_addr
- topo_node_sqlite.c, member_sync.c: remove addr_type=0 filter from SELECT/DELETE
- chat_profile.c, member_sync.c: DELETE all addresses (not just addr_type=0)
topo_upd
evgeny 2 months ago
parent
commit
25ebad9f52
  1. 24
      src/chat/chat_core_priv.h
  2. 28
      src/chat/chat_profile.c
  3. 35
      src/chat/chat_sync.c
  4. 16
      src/chat/member_sync.c
  5. 2
      src/routing_layer/topo_node_sqlite.c
  6. 13
      src/transport_layer/etcp_connections.c
  7. 4
      src/transport_layer/etcp_connections.h
  8. 31
      tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/MemberListScreen.kt

24
src/chat/chat_core_priv.h

@ -73,6 +73,30 @@ static inline size_t b64_decode(const char* src, size_t src_len, uint8_t* dst, s
return out; return out;
} }
/* ── addr_type classification ── */
#include "../routing_layer/topo_node.h"
static inline int addr_type_from_ip(int family, const uint8_t* addr) {
if (!addr) return ADDR_TYPE_NETIF;
if (family == 4) {
uint8_t b0 = addr[0], b1 = addr[1];
if (b0 == 0 || b0 == 10 || b0 == 127) return ADDR_TYPE_NETIF;
if (b0 == 169 && b1 == 254) return ADDR_TYPE_NETIF;
if (b0 >= 224 && b0 <= 239) return ADDR_TYPE_NETIF;
if (b0 == 172 && b1 >= 16 && b1 <= 31) return ADDR_TYPE_NETIF;
if (b0 == 192 && b1 == 168) return ADDR_TYPE_NETIF;
{ uint32_t ip; memcpy(&ip, addr, 4); if (ip == 0 || ip == 0xffffffff) return ADDR_TYPE_NETIF; }
return ADDR_TYPE_DIRECT;
} else {
if (addr[0] == 0xfe && (addr[1] & 0xc0) == 0x80) return ADDR_TYPE_NETIF;
if (addr[0] == 0xfc || addr[0] == 0xfd) return ADDR_TYPE_NETIF;
{ static const uint8_t z[16]; if (!memcmp(addr, z, 16)) return ADDR_TYPE_NETIF; }
{ static const uint8_t lb[16]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1}; if (!memcmp(addr,lb,16)) return ADDR_TYPE_NETIF; }
return ADDR_TYPE_DIRECT;
}
}
/* ── Глобальное состояние (определено в chat_core.c) ── */ /* ── Глобальное состояние (определено в chat_core.c) ── */
struct chat_core_ctx { struct chat_core_ctx {

28
src/chat/chat_profile.c

@ -95,19 +95,19 @@ void chat_core_sync_my_addresses(void) {
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] sync_my_addresses START my_node=0x%016llx", CC_ID, (unsigned long long)g_cc.my_node_id); DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] sync_my_addresses START my_node=0x%016llx", CC_ID, (unsigned long long)g_cc.my_node_id);
sqlite3_stmt* del = NULL; sqlite3_stmt* del = NULL;
sqlite3_prepare_v2(g_cc.db, "DELETE FROM node_addresses WHERE node_id=? AND addr_type=0", -1, &del, NULL); sqlite3_prepare_v2(g_cc.db, "DELETE FROM node_addresses WHERE node_id=?", -1, &del, NULL);
if (del) { if (del) {
sqlite3_bind_int64(del, 1, (sqlite3_int64)g_cc.my_node_id); sqlite3_bind_int64(del, 1, (sqlite3_int64)g_cc.my_node_id);
sqlite3_step(del); sqlite3_step(del);
int deleted = sqlite3_changes(g_cc.db); int deleted = sqlite3_changes(g_cc.db);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] DELETE addr_type=0 for my_node=0x%016llx: %d rows deleted", CC_ID, (unsigned long long)g_cc.my_node_id, deleted); DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] DELETE for my_node=0x%016llx: %d rows deleted", CC_ID, (unsigned long long)g_cc.my_node_id, deleted);
sqlite3_finalize(del); sqlite3_finalize(del);
} }
sqlite3_stmt* ins = NULL; sqlite3_stmt* ins = NULL;
sqlite3_prepare_v2(g_cc.db, sqlite3_prepare_v2(g_cc.db,
"INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)" "INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)"
" VALUES(?,?,1,?,?,0,?)", -1, &ins, NULL); " VALUES(?,?,1,?,?,?,?)", -1, &ins, NULL);
if (!ins) { if (!ins) {
DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] FAIL prepare INSERT stmt my_node=0x%016llx", CC_ID, (unsigned long long)g_cc.my_node_id); DEBUG_WARN(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] FAIL prepare INSERT stmt my_node=0x%016llx", CC_ID, (unsigned long long)g_cc.my_node_id);
return; return;
@ -129,7 +129,8 @@ void chat_core_sync_my_addresses(void) {
sqlite3_bind_int(ins, 2, 4); sqlite3_bind_int(ins, 2, 4);
sqlite3_bind_blob(ins, 3, &sin->sin_addr, 4, SQLITE_STATIC); sqlite3_bind_blob(ins, 3, &sin->sin_addr, 4, SQLITE_STATIC);
sqlite3_bind_int(ins, 4, (int)ntohs(sin->sin_port)); sqlite3_bind_int(ins, 4, (int)ntohs(sin->sin_port));
sqlite3_bind_int(ins, 5, (int)sock->sock_id); sqlite3_bind_int(ins, 5, addr_type_from_ip(4, (const uint8_t*)&sin->sin_addr));
sqlite3_bind_int(ins, 6, (int)sock->sock_id);
sqlite3_step(ins); sqlite3_reset(ins); sqlite3_step(ins); sqlite3_reset(ins);
uint8_t* ip = (uint8_t*)&sin->sin_addr; uint8_t* ip = (uint8_t*)&sin->sin_addr;
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INSERT my_node=0x%016llx sock=%d %d.%d.%d.%d:%d", DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INSERT my_node=0x%016llx sock=%d %d.%d.%d.%d:%d",
@ -141,7 +142,8 @@ void chat_core_sync_my_addresses(void) {
sqlite3_bind_int(ins, 2, 6); sqlite3_bind_int(ins, 2, 6);
sqlite3_bind_blob(ins, 3, &sin6->sin6_addr, 16, SQLITE_STATIC); sqlite3_bind_blob(ins, 3, &sin6->sin6_addr, 16, SQLITE_STATIC);
sqlite3_bind_int(ins, 4, (int)ntohs(sin6->sin6_port)); sqlite3_bind_int(ins, 4, (int)ntohs(sin6->sin6_port));
sqlite3_bind_int(ins, 5, (int)sock->sock_id); sqlite3_bind_int(ins, 5, addr_type_from_ip(6, sin6->sin6_addr.s6_addr));
sqlite3_bind_int(ins, 6, (int)sock->sock_id);
sqlite3_step(ins); sqlite3_reset(ins); sqlite3_step(ins); sqlite3_reset(ins);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INSERT v6 my_node=0x%016llx sock=%d port=%d", DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INSERT v6 my_node=0x%016llx sock=%d port=%d",
CC_ID, (unsigned long long)g_cc.my_node_id, sock->sock_id, (int)ntohs(sin6->sin6_port)); CC_ID, (unsigned long long)g_cc.my_node_id, sock->sock_id, (int)ntohs(sin6->sin6_port));
@ -154,7 +156,7 @@ void chat_core_sync_my_addresses(void) {
{ sqlite3_stmt* tcp_ins = NULL; { sqlite3_stmt* tcp_ins = NULL;
sqlite3_prepare_v2(g_cc.db, sqlite3_prepare_v2(g_cc.db,
"INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)" "INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)"
" VALUES(?,?,2,?,?,0,?)", -1, &tcp_ins, NULL); " VALUES(?,?,2,?,?,?,?)", -1, &tcp_ins, NULL);
if (tcp_ins) { if (tcp_ins) {
struct TCP_SOCKET* ts = g_cc.inst->tcp_sockets; struct TCP_SOCKET* ts = g_cc.inst->tcp_sockets;
int tcp_count = 0; int tcp_count = 0;
@ -164,12 +166,13 @@ void chat_core_sync_my_addresses(void) {
if (!addr || !addr->ss_family) { ts = ts->next; continue; } if (!addr || !addr->ss_family) { ts = ts->next; continue; }
if (addr->ss_family == AF_INET) { if (addr->ss_family == AF_INET) {
struct sockaddr_in* sin = (struct sockaddr_in*)addr; struct sockaddr_in* sin = (struct sockaddr_in*)addr;
if (sin->sin_addr.s_addr == 0) { ts = ts->next; continue; } // skip 0.0.0.0 if (sin->sin_addr.s_addr == 0) { ts = ts->next; continue; }
sqlite3_bind_int64(tcp_ins, 1, (sqlite3_int64)g_cc.my_node_id); sqlite3_bind_int64(tcp_ins, 1, (sqlite3_int64)g_cc.my_node_id);
sqlite3_bind_int(tcp_ins, 2, 4); sqlite3_bind_int(tcp_ins, 2, 4);
sqlite3_bind_blob(tcp_ins, 3, &sin->sin_addr, 4, SQLITE_STATIC); sqlite3_bind_blob(tcp_ins, 3, &sin->sin_addr, 4, SQLITE_STATIC);
sqlite3_bind_int(tcp_ins, 4, (int)ntohs(sin->sin_port)); sqlite3_bind_int(tcp_ins, 4, (int)ntohs(sin->sin_port));
sqlite3_bind_int(tcp_ins, 5, (int)ts->sock_id); sqlite3_bind_int(tcp_ins, 5, addr_type_from_ip(4, (const uint8_t*)&sin->sin_addr));
sqlite3_bind_int(tcp_ins, 6, (int)ts->sock_id);
sqlite3_step(tcp_ins); sqlite3_reset(tcp_ins); sqlite3_step(tcp_ins); sqlite3_reset(tcp_ins);
uint8_t* ip = (uint8_t*)&sin->sin_addr; uint8_t* ip = (uint8_t*)&sin->sin_addr;
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INSERT TCP my_node=0x%016llx sock=%d %d.%d.%d.%d:%d", DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INSERT TCP my_node=0x%016llx sock=%d %d.%d.%d.%d:%d",
@ -177,12 +180,13 @@ void chat_core_sync_my_addresses(void) {
tcp_written++; tcp_written++;
} else if (addr->ss_family == AF_INET6) { } else if (addr->ss_family == AF_INET6) {
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr; struct sockaddr_in6* sin6 = (struct sockaddr_in6*)addr;
if (memcmp(&sin6->sin6_addr, &in6addr_any, 16) == 0) { ts = ts->next; continue; } // skip :: if (memcmp(&sin6->sin6_addr, &in6addr_any, 16) == 0) { ts = ts->next; continue; }
sqlite3_bind_int64(tcp_ins, 1, (sqlite3_int64)g_cc.my_node_id); sqlite3_bind_int64(tcp_ins, 1, (sqlite3_int64)g_cc.my_node_id);
sqlite3_bind_int(tcp_ins, 2, 6); sqlite3_bind_int(tcp_ins, 2, 6);
sqlite3_bind_blob(tcp_ins, 3, &sin6->sin6_addr, 16, SQLITE_STATIC); sqlite3_bind_blob(tcp_ins, 3, &sin6->sin6_addr, 16, SQLITE_STATIC);
sqlite3_bind_int(tcp_ins, 4, (int)ntohs(sin6->sin6_port)); sqlite3_bind_int(tcp_ins, 4, (int)ntohs(sin6->sin6_port));
sqlite3_bind_int(tcp_ins, 5, (int)ts->sock_id); sqlite3_bind_int(tcp_ins, 5, addr_type_from_ip(6, sin6->sin6_addr.s6_addr));
sqlite3_bind_int(tcp_ins, 6, (int)ts->sock_id);
sqlite3_step(tcp_ins); sqlite3_reset(tcp_ins); sqlite3_step(tcp_ins); sqlite3_reset(tcp_ins);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INSERT TCP v6 my_node=0x%016llx sock=%d port=%d", DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INSERT TCP v6 my_node=0x%016llx sock=%d port=%d",
CC_ID, (unsigned long long)g_cc.my_node_id, ts->sock_id, (int)ntohs(sin6->sin6_port)); CC_ID, (unsigned long long)g_cc.my_node_id, ts->sock_id, (int)ntohs(sin6->sin6_port));
@ -205,11 +209,11 @@ void chat_core_sync_my_addresses(void) {
CC_ID, written, tcp_written, written + tcp_written, skipped, (unsigned long long)g_cc.my_node_id); CC_ID, written, tcp_written, written + tcp_written, skipped, (unsigned long long)g_cc.my_node_id);
sqlite3_stmt* chk = NULL; sqlite3_stmt* chk = NULL;
sqlite3_prepare_v2(g_cc.db, "SELECT COUNT(*) FROM node_addresses WHERE node_id=? AND addr_type=0", -1, &chk, NULL); sqlite3_prepare_v2(g_cc.db, "SELECT COUNT(*) FROM node_addresses WHERE node_id=?", -1, &chk, NULL);
if (chk) { if (chk) {
sqlite3_bind_int64(chk, 1, (sqlite3_int64)g_cc.my_node_id); sqlite3_bind_int64(chk, 1, (sqlite3_int64)g_cc.my_node_id);
int cnt = sqlite3_step(chk) == SQLITE_ROW ? sqlite3_column_int(chk, 0) : -1; int cnt = sqlite3_step(chk) == SQLITE_ROW ? sqlite3_column_int(chk, 0) : -1;
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] VERIFY: total addr_type=0 rows for my_node=0x%016llx = %d", DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] VERIFY: total rows for my_node=0x%016llx = %d",
CC_ID, (unsigned long long)g_cc.my_node_id, cnt); CC_ID, (unsigned long long)g_cc.my_node_id, cnt);
sqlite3_finalize(chk); sqlite3_finalize(chk);
} }

35
src/chat/chat_sync.c

@ -1,5 +1,6 @@
#include "chat_sync.h" #include "chat_sync.h"
#include "chat_core.h" #include "chat_core.h"
#include "chat_core_priv.h"
#include "chat_setting.h" #include "chat_setting.h"
#include "chat_event.h" #include "chat_event.h"
#include "../routing_layer/topo_node_sqlite.h" #include "../routing_layer/topo_node_sqlite.h"
@ -1063,13 +1064,14 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
struct sockaddr_in* sin = (struct sockaddr_in*)&lk->remote_addr; struct sockaddr_in* sin = (struct sockaddr_in*)&lk->remote_addr;
uint8_t ip[4]; memcpy(ip, &sin->sin_addr, 4); uint16_t port = ntohs(sin->sin_port); uint8_t ip[4]; memcpy(ip, &sin->sin_addr, 4); uint16_t port = ntohs(sin->sin_port);
char sql[256]; snprintf(sql, sizeof(sql), char sql[256]; snprintf(sql, sizeof(sql),
"INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id) VALUES(?,4,1,?,?,0,?)"); "INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id) VALUES(?,4,1,?,?,?,?)");
sqlite3_stmt* as = NULL; sqlite3_stmt* as = NULL;
if (sqlite3_prepare_v2(vdb, sql, -1, &as, NULL) == SQLITE_OK) { if (sqlite3_prepare_v2(vdb, sql, -1, &as, NULL) == SQLITE_OK) {
sqlite3_bind_int64(as, 1, (sqlite3_int64)peer); sqlite3_bind_int64(as, 1, (sqlite3_int64)peer);
sqlite3_bind_blob(as, 2, ip, 4, SQLITE_STATIC); sqlite3_bind_blob(as, 2, ip, 4, SQLITE_STATIC);
sqlite3_bind_int(as, 3, port); sqlite3_bind_int(as, 3, port);
sqlite3_bind_int(as, 4, (int)lk->conn->sock_id); sqlite3_bind_int(as, 4, addr_type_from_ip(4, ip));
sqlite3_bind_int(as, 5, (int)lk->conn->sock_id);
sqlite3_step(as); sqlite3_finalize(as); sqlite3_step(as); sqlite3_finalize(as);
lk_written++; lk_written++;
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INFO_RESP INSERT peer=%016llx sock=%d %d.%d.%d.%d:%d", DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] INFO_RESP INSERT peer=%016llx sock=%d %d.%d.%d.%d:%d",
@ -1122,10 +1124,16 @@ static void cs_handle_channel_info_resp(struct chat_sync* cs, uint64_t peer,
jbuf[joff++] = 0; jbuf[joff++] = 0;
struct ETCP_SOCKET* sock = cs->inst->etcp_sockets; struct ETCP_SOCKET* sock = cs->inst->etcp_sockets;
while (sock && addr_cnt < 255) { while (sock && addr_cnt < 255) {
struct sockaddr_storage* sa; struct sockaddr_storage* sa = NULL;
if (sock->nat_addr.ss_family) sa = &sock->nat_addr; if (sock->nat_addr.ss_family) {
else if (sock->interface_addr.ss_family) sa = &sock->interface_addr; sa = &sock->nat_addr;
else { sock = sock->next; continue; } int is_zero = 0;
if (sa->ss_family == AF_INET) { if (((struct sockaddr_in*)sa)->sin_addr.s_addr == 0) is_zero = 1; }
else { static const uint8_t z[16]; if (!memcmp(&((struct sockaddr_in6*)sa)->sin6_addr, z, 16)) is_zero = 1; }
if (is_zero) sa = NULL;
}
if (!sa && sock->interface_addr.ss_family) sa = &sock->interface_addr;
if (!sa) { sock = sock->next; continue; }
if (sa->ss_family == AF_INET) { if (sa->ss_family == AF_INET) {
struct sockaddr_in* sin = (struct sockaddr_in*)sa; struct sockaddr_in* sin = (struct sockaddr_in*)sa;
if (joff + 9 > sizeof(jbuf)) break; if (joff + 9 > sizeof(jbuf)) break;
@ -1214,7 +1222,7 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
char sql[256]; snprintf(sql, sizeof(sql), char sql[256]; snprintf(sql, sizeof(sql),
"INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)" "INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)"
" VALUES(?,?,?,?,?,0,?)"); " VALUES(?,?,?,?,?,?,?)");
sqlite3_stmt* stmt = NULL; sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) { if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id); sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id);
@ -1222,7 +1230,8 @@ static void cs_handle_channel_join(struct chat_sync* cs, uint64_t peer,
sqlite3_bind_int(stmt, 3, (int)proto); sqlite3_bind_int(stmt, 3, (int)proto);
sqlite3_bind_blob(stmt, 4, ip, ip_len, SQLITE_STATIC); sqlite3_bind_blob(stmt, 4, ip, ip_len, SQLITE_STATIC);
sqlite3_bind_int(stmt, 5, (int)port); sqlite3_bind_int(stmt, 5, (int)port);
sqlite3_bind_int(stmt, 6, (int)sid); sqlite3_bind_int(stmt, 6, addr_type_from_ip(fm, ip));
sqlite3_bind_int(stmt, 7, (int)sid);
sqlite3_step(stmt); sqlite3_finalize(stmt); sqlite3_step(stmt); sqlite3_finalize(stmt);
} }
if (fm == 4) if (fm == 4)
@ -1389,7 +1398,7 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
char sql[256]; snprintf(sql, sizeof(sql), char sql[256]; snprintf(sql, sizeof(sql),
"INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)" "INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)"
" VALUES(?,?,?,?,?,0,?)"); " VALUES(?,?,?,?,?,?,?)");
sqlite3_stmt* stmt2 = NULL; sqlite3_stmt* stmt2 = NULL;
if (sqlite3_prepare_v2(db, sql, -1, &stmt2, NULL) == SQLITE_OK) { if (sqlite3_prepare_v2(db, sql, -1, &stmt2, NULL) == SQLITE_OK) {
sqlite3_bind_int64(stmt2, 1, (sqlite3_int64)node_id); sqlite3_bind_int64(stmt2, 1, (sqlite3_int64)node_id);
@ -1397,7 +1406,8 @@ static void cs_handle_welcome(struct chat_sync* cs, uint64_t peer,
sqlite3_bind_int(stmt2, 3, (int)proto); sqlite3_bind_int(stmt2, 3, (int)proto);
sqlite3_bind_blob(stmt2, 4, ip, ip_len, SQLITE_STATIC); sqlite3_bind_blob(stmt2, 4, ip, ip_len, SQLITE_STATIC);
sqlite3_bind_int(stmt2, 5, (int)port); sqlite3_bind_int(stmt2, 5, (int)port);
sqlite3_bind_int(stmt2, 6, (int)sid); sqlite3_bind_int(stmt2, 6, addr_type_from_ip(fm, ip));
sqlite3_bind_int(stmt2, 7, (int)sid);
sqlite3_step(stmt2); sqlite3_finalize(stmt2); sqlite3_step(stmt2); sqlite3_finalize(stmt2);
} }
if (fm == 4) if (fm == 4)
@ -1503,7 +1513,7 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer,
char sql[256]; snprintf(sql, sizeof(sql), char sql[256]; snprintf(sql, sizeof(sql),
"INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)" "INSERT OR REPLACE INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)"
" VALUES(?,?,?,?,?,0,?)"); " VALUES(?,?,?,?,?,?,?)");
sqlite3_stmt* stmt = NULL; sqlite3_stmt* stmt = NULL;
if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) { if (sqlite3_prepare_v2(db, sql, -1, &stmt, NULL) == SQLITE_OK) {
sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id); sqlite3_bind_int64(stmt, 1, (sqlite3_int64)node_id);
@ -1511,7 +1521,8 @@ static void cs_handle_peer_upsert(struct chat_sync* cs, uint64_t peer,
sqlite3_bind_int(stmt, 3, (int)proto); sqlite3_bind_int(stmt, 3, (int)proto);
sqlite3_bind_blob(stmt, 4, ip, ip_len, SQLITE_STATIC); sqlite3_bind_blob(stmt, 4, ip, ip_len, SQLITE_STATIC);
sqlite3_bind_int(stmt, 5, (int)port); sqlite3_bind_int(stmt, 5, (int)port);
sqlite3_bind_int(stmt, 6, (int)sid); sqlite3_bind_int(stmt, 6, addr_type_from_ip(fm, ip));
sqlite3_bind_int(stmt, 7, (int)sid);
sqlite3_step(stmt); sqlite3_finalize(stmt); sqlite3_step(stmt); sqlite3_finalize(stmt);
} }
if (fm == 4) if (fm == 4)

16
src/chat/member_sync.c

@ -1,7 +1,8 @@
#include "member_sync.h" #include "member_sync.h"
#include "../routing_layer/topo_node_sqlite.h" #include "../routing_layer/topo_node_sqlite.h"
#include "chat_core.h" #include "chat_core.h"
#include "chat_core_priv.h"
#include "../utun_instance.h" #include "../utun_instance.h"
#include "../../lib/debug_config.h" #include "../../lib/debug_config.h"
#include "../../lib/mem.h" #include "../../lib/mem.h"
@ -130,7 +131,7 @@ static int _member_update_bucket_hash(void* ctx, const char* ns, uint8_t level,
uint8_t addrs[2048]; int addr_off = 0; int addr_count = 0; uint8_t addrs[2048]; int addr_off = 0; int addr_count = 0;
sqlite3_stmt* as = NULL; sqlite3_stmt* as = NULL;
sqlite3_prepare_v2(db, sqlite3_prepare_v2(db,
"SELECT family, socket_id, protocol, address, port FROM node_addresses WHERE node_id=? AND addr_type=0" "SELECT family, socket_id, protocol, address, port FROM node_addresses WHERE node_id=?"
" ORDER BY family, address, port", -1, &as, NULL); " ORDER BY family, address, port", -1, &as, NULL);
if (as) { if (as) {
sqlite3_bind_int64(as, 1, (sqlite3_int64)nid); sqlite3_bind_int64(as, 1, (sqlite3_int64)nid);
@ -205,7 +206,7 @@ static int _member_get_items(void* ctx, const char* ns, uint8_t level,
sqlite3_stmt* as = NULL; sqlite3_stmt* as = NULL;
sqlite3_prepare_v2(db, sqlite3_prepare_v2(db,
"SELECT family, socket_id, protocol, address, port FROM node_addresses WHERE node_id=? AND addr_type=0" "SELECT family, socket_id, protocol, address, port FROM node_addresses WHERE node_id=?"
" ORDER BY family, address, port", -1, &as, NULL); " ORDER BY family, address, port", -1, &as, NULL);
uint8_t addrs[2048]; int addr_off = 0; int addr_count = 0; uint8_t addrs[2048]; int addr_off = 0; int addr_count = 0;
if (as) { if (as) {
@ -528,17 +529,17 @@ int member_sync_put(struct UTUN_INSTANCE* inst, const char* ch_id,
MS_ID, (unsigned long long)member_id, ch_id, addr_count); MS_ID, (unsigned long long)member_id, ch_id, addr_count);
sqlite3_exec(db, "BEGIN", NULL, NULL, NULL); sqlite3_exec(db, "BEGIN", NULL, NULL, NULL);
sqlite3_stmt* ds = NULL; sqlite3_stmt* ds = NULL;
sqlite3_prepare_v2(db, "DELETE FROM node_addresses WHERE node_id=? AND addr_type=0", -1, &ds, NULL); sqlite3_prepare_v2(db, "DELETE FROM node_addresses WHERE node_id=?", -1, &ds, NULL);
if (ds) { sqlite3_bind_int64(ds, 1, (sqlite3_int64)member_id); sqlite3_step(ds); if (ds) { sqlite3_bind_int64(ds, 1, (sqlite3_int64)member_id); sqlite3_step(ds);
int deleted = sqlite3_changes(db); int deleted = sqlite3_changes(db);
DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] member_sync_put DELETE addr_type=0 node=0x%016llx: %d rows deleted", DEBUG_INFO(DEBUG_CATEGORY_MEMBER_SYNC, "%s: [ADDR_SYNC] member_sync_put DELETE node=0x%016llx: %d rows deleted",
MS_ID, (unsigned long long)member_id, deleted); MS_ID, (unsigned long long)member_id, deleted);
sqlite3_finalize(ds); } sqlite3_finalize(ds); }
sqlite3_stmt* as = NULL; sqlite3_stmt* as = NULL;
sqlite3_prepare_v2(db, sqlite3_prepare_v2(db,
"INSERT INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)" "INSERT INTO node_addresses(node_id,family,protocol,address,port,addr_type,socket_id)"
" VALUES(?,?,?,?,?,0,?)", -1, &as, NULL); " VALUES(?,?,?,?,?,?,?)", -1, &as, NULL);
if (as) { if (as) {
const uint8_t* p = addrs_data; const uint8_t* p = addrs_data;
int written = 0; int written = 0;
@ -554,7 +555,8 @@ int member_sync_put(struct UTUN_INSTANCE* inst, const char* ch_id,
p += ip_sz; p += ip_sz;
uint16_t port = ((uint16_t)p[0] << 8) | p[1]; p += 2; uint16_t port = ((uint16_t)p[0] << 8) | p[1]; p += 2;
sqlite3_bind_int(as, 5, port); sqlite3_bind_int(as, 5, port);
sqlite3_bind_int(as, 6, (int)sid); sqlite3_bind_int(as, 6, addr_type_from_ip(fam, p - ip_sz - 2));
sqlite3_bind_int(as, 7, (int)sid);
sqlite3_step(as); sqlite3_reset(as); sqlite3_step(as); sqlite3_reset(as);
if (fam == 4) { if (fam == 4) {
const uint8_t* ip = p - 6; /* p advanced by ip_sz(4) + port(2) - back to start of ip */ const uint8_t* ip = p - 6; /* p advanced by ip_sz(4) + port(2) - back to start of ip */

2
src/routing_layer/topo_node_sqlite.c

@ -383,7 +383,7 @@ int topo_node_sqlite_channel_peers_all(sqlite3* db, const char* channel_id,
sqlite3_stmt* ast = NULL; sqlite3_stmt* ast = NULL;
snprintf(sql, sizeof(sql), snprintf(sql, sizeof(sql),
"SELECT family, socket_id, protocol, address, port FROM node_addresses" "SELECT family, socket_id, protocol, address, port FROM node_addresses"
" WHERE node_id=? AND addr_type=0 LIMIT 16"); " WHERE node_id=? LIMIT 16");
if (sqlite3_prepare_v2(db, sql, -1, &ast, NULL) != SQLITE_OK) continue; if (sqlite3_prepare_v2(db, sql, -1, &ast, NULL) != SQLITE_OK) continue;
sqlite3_bind_int64(ast, 1, (sqlite3_int64)node_id); sqlite3_bind_int64(ast, 1, (sqlite3_int64)node_id);

13
src/transport_layer/etcp_connections.c

@ -1045,7 +1045,8 @@ int etcp_encrypt_send(struct ETCP_DGRAM* dgram) {
int errcode=0; int errcode=0;
sc_context_t* sc = &dgram->link->etcp->crypto_ctx; sc_context_t* sc = &dgram->link->etcp->crypto_ctx;
int len=dgram->data_len-dgram->noencrypt_len;// не забываем добавить timestamp (2 bytes) int len=dgram->data_len-dgram->noencrypt_len;// не забываем добавить timestamp (2 bytes)
if (len<0 || len>dgram->link->mtu - UDP_HDR_SIZE) { dgram->link->send_errors++; errcode=1; goto es_err; } int wire_ov = WIRE_OVERHEAD(dgram->link->remote_addr.ss_family);
if (len<0 || len>dgram->link->mtu - wire_ov) { dgram->link->send_errors++; errcode=1; goto es_err; }
uint8_t enc_buf[1600]; uint8_t enc_buf[1600];
size_t enc_buf_len=0; size_t enc_buf_len=0;
dgram->timestamp=get_current_timestamp(); dgram->timestamp=get_current_timestamp();
@ -1480,13 +1481,17 @@ static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pk
int xoffset=sizeof(struct ETCP_INIT_RESPONSE_PKT); int xoffset=sizeof(struct ETCP_INIT_RESPONSE_PKT);
// padding // padding
int wire_ov = WIRE_OVERHEAD(link->remote_addr.ss_family);
int max_data = link->mtu - wire_ov;
int s = rand() % (link->handshake_maxsize - link->handshake_minsize) + link->handshake_minsize; int s = rand() % (link->handshake_maxsize - link->handshake_minsize) + link->handshake_minsize;
if (s > (int)(link->mtu)) s = (int)(link->mtu); if (s > (int)(link->mtu)) s = (int)(link->mtu);
if (s < 0) s = 0; if (s < 0) s = 0;
int to_add=s - xoffset - UDP_HDR_SIZE - UDP_SC_HDR_SIZE; int to_add = s - xoffset - wire_ov;
if (to_add<0) to_add=0; if (to_add < 0) to_add = 0;
if (xoffset + to_add > PACKET_DATA_SIZE) { to_add = PACKET_DATA_SIZE - xoffset; if (to_add<0) to_add=0; } if (xoffset + to_add > PACKET_DATA_SIZE) { to_add = PACKET_DATA_SIZE - xoffset; if (to_add < 0) to_add = 0; }
if (xoffset + to_add > max_data) to_add = max_data - xoffset;
if (to_add < 0) to_add = 0;
for (int i=0; i<to_add; i++) pkt->data[xoffset++]=rand();// fill pad for (int i=0; i<to_add; i++) pkt->data[xoffset++]=rand();// fill pad
// padding end // padding end

4
src/transport_layer/etcp_connections.h

@ -19,6 +19,10 @@ extern "C" {
#define UDP_HDR_SIZE 28// размер udp header + ethernet заголовков (ipv4) [для ipv6 = 48 байт] #define UDP_HDR_SIZE 28// размер udp header + ethernet заголовков (ipv4) [для ipv6 = 48 байт]
#define UDP_SC_HDR_SIZE (13+8+4 + 5)// 13+8+4 - sc_nonce+tag size+crc, 5 - payload hdr #define UDP_SC_HDR_SIZE (13+8+4 + 5)// 13+8+4 - sc_nonce+tag size+crc, 5 - payload hdr
#define ACK_REZERV 100// сколько байт резервировать под ack и прочие заголовки #define ACK_REZERV 100// сколько байт резервировать под ack и прочие заголовки
#define SC_ENCRYPT_OVERHEAD (3 + SC_TAG_SIZE) // timestamp(2)+flag_up(1)+AES-CCM tag(16) — поверх plaintext
#define IP_UDP_OVERHEAD_V4 (20 + 8) // IP(20)+UDP(8)
#define IP_UDP_OVERHEAD_V6 (40 + 8) // IP(40)+UDP(8)
#define WIRE_OVERHEAD(fam) ((fam) == AF_INET6 ? IP_UDP_OVERHEAD_V6 + SC_ENCRYPT_OVERHEAD : IP_UDP_OVERHEAD_V4 + SC_ENCRYPT_OVERHEAD)
#define INFLIGHT_LIM_MIN 8192 // 8K #define INFLIGHT_LIM_MIN 8192 // 8K
#define INFLIGHT_LIM_MAX 1048576 // 1M #define INFLIGHT_LIM_MAX 1048576 // 1M

31
tools/chatgui-android/app/src/main/java/com/utun/chat/ui/screens/MemberListScreen.kt

@ -89,6 +89,7 @@ fun MemberListScreen(
MemberDetailCard( MemberDetailCard(
detail = detail, detail = detail,
memberLinks = memberLinks, memberLinks = memberLinks,
isSelf = members.any { it.nodeId == detail.nodeId && it.isSelf },
onDismiss = { } onDismiss = { }
) )
} }
@ -140,12 +141,16 @@ private fun MemberListItem(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp), modifier = Modifier.padding(horizontal = 16.dp, vertical = 10.dp),
verticalAlignment = Alignment.CenterVertically verticalAlignment = Alignment.CenterVertically
) { ) {
if (member.isSelf) {
Text("✓", fontSize = 12.sp, color = Color(0xFF4CAF50))
} else {
Box( Box(
modifier = Modifier modifier = Modifier
.size(10.dp) .size(10.dp)
.clip(CircleShape) .clip(CircleShape)
.background(onlineColor) .background(onlineColor)
) )
}
Spacer(Modifier.width(10.dp)) Spacer(Modifier.width(10.dp))
Column(modifier = Modifier.weight(1f)) { Column(modifier = Modifier.weight(1f)) {
@ -161,7 +166,8 @@ private fun MemberListItem(
if (member.isAdmin) parts.add("Admin") if (member.isAdmin) parts.add("Admin")
if (member.isSuper) parts.add("Super") if (member.isSuper) parts.add("Super")
if (member.isStorage) parts.add("Storage") if (member.isStorage) parts.add("Storage")
if (member.directUp) parts.add("direct↑") if (member.isSelf) parts.add("self")
else if (member.directUp) parts.add("direct↑")
else if (member.indirectUp) parts.add("indirect↑") else if (member.indirectUp) parts.add("indirect↑")
else if (member.directPresence || member.indirectPresence || member.bgpPresence) parts.add("down") else if (member.directPresence || member.indirectPresence || member.bgpPresence) parts.add("down")
if (member.rtt > 0) parts.add("${member.rtt}ms") if (member.rtt > 0) parts.add("${member.rtt}ms")
@ -170,7 +176,7 @@ private fun MemberListItem(
Text( Text(
text = parts.joinToString(" "), text = parts.joinToString(" "),
fontSize = 11.sp, fontSize = 11.sp,
color = if (member.directUp || member.indirectUp) color = if (member.isSelf || member.directUp || member.indirectUp)
Color(0xFF4CAF50) else Color.Gray Color(0xFF4CAF50) else Color.Gray
) )
} }
@ -186,6 +192,7 @@ private fun MemberListItem(
private fun MemberDetailCard( private fun MemberDetailCard(
detail: MemberDetail, detail: MemberDetail,
memberLinks: MemberLinks, memberLinks: MemberLinks,
isSelf: Boolean = false,
onDismiss: () -> Unit onDismiss: () -> Unit
) { ) {
fun linkDotColor(addr: MemberAddr): Color { fun linkDotColor(addr: MemberAddr): Color {
@ -247,6 +254,15 @@ private fun MemberDetailCard(
Spacer(Modifier.height(6.dp)) Spacer(Modifier.height(6.dp))
Text("Addresses:", fontSize = 13.sp, fontWeight = FontWeight.Medium) Text("Addresses:", fontSize = 13.sp, fontWeight = FontWeight.Medium)
detail.addresses.forEach { a -> detail.addresses.forEach { a ->
if (isSelf) {
Text(
text = "${a.protocol} ${a.address}:${a.port}" +
(if (a.rtt > 0) " (${a.rtt / 10}ms)" else ""),
fontFamily = FontFamily.Monospace,
fontSize = 11.sp,
color = Color.DarkGray
)
} else {
val dcol = linkDotColor(a) val dcol = linkDotColor(a)
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Box( Box(
@ -266,10 +282,17 @@ private fun MemberDetailCard(
} }
} }
} }
}
val rttTypeName = when (detail.rttType) { 0 -> "interface" 1 -> "nat" 2 -> "real" else -> "?" } val rttTypeName = when (detail.rttType) { 0 -> "interface" 1 -> "nat" 2 -> "real" else -> "?" }
Spacer(Modifier.height(6.dp)) Spacer(Modifier.height(6.dp))
Text("Connection:", fontSize = 13.sp, fontWeight = FontWeight.Medium) Text("Connection:", fontSize = 13.sp, fontWeight = FontWeight.Medium)
if (detail.directPresence) { if (isSelf) {
Row(verticalAlignment = Alignment.CenterVertically) {
Text("✓", fontSize = 12.sp, color = Color(0xFF4CAF50))
Spacer(Modifier.width(4.dp))
Text("self (local)", fontSize = 12.sp, color = Color(0xFF4CAF50))
}
} else if (detail.directPresence) {
Row(verticalAlignment = Alignment.CenterVertically) { Row(verticalAlignment = Alignment.CenterVertically) {
Box(Modifier.size(8.dp).clip(CircleShape) Box(Modifier.size(8.dp).clip(CircleShape)
.background(if (detail.directUp) Color(0xFF4CAF50) else Color(0xFFE53935))) .background(if (detail.directUp) Color(0xFF4CAF50) else Color(0xFFE53935)))
@ -295,7 +318,7 @@ private fun MemberDetailCard(
Text("BGP: visible", fontSize = 12.sp, color = Color.DarkGray) Text("BGP: visible", fontSize = 12.sp, color = Color.DarkGray)
} }
} }
if (!detail.directPresence && !detail.indirectPresence && !detail.bgpPresence) { if (!isSelf && !detail.directPresence && !detail.indirectPresence && !detail.bgpPresence) {
Text("offline", fontSize = 12.sp, color = Color.Gray) Text("offline", fontSize = 12.sp, color = Color.Gray)
} }
} }

Loading…
Cancel
Save