Browse Source

fix: auto_socket TCP duplicate sockets + NAT v4 address resolution

auto_socket.c: create_iface_tcp_socket returns stcp_server* instead of int,
ifa->v4_tcp/ifa->v6_tcp now properly track the created server, preventing
duplicate bind/listen on every reconcile_iface call.

etcp_connections.c: tcp_socket_add now resolves interface_addr via
get_interface_ip_by_index/get_interface_ipv6_addr_nl for any type (not just
PUBLIC), preventing NAT TCP v4 sockets from being destroyed due to INADDR_ANY.
topo_upd
evgeny 2 months ago
parent
commit
80e77f12c2
  1. 26
      src/routing_layer/conn_mgr_core.c
  2. 14
      src/routing_layer/topo_node_sqlite.c
  3. 24
      src/transport_layer/auto_socket.c
  4. 4
      src/transport_layer/auto_socket.h
  5. 31
      src/transport_layer/etcp_connections.c
  6. 3
      src/transport_layer/etcp_connections.h
  7. 2
      src/transport_layer/stcp.c
  8. 24
      src/transport_layer/stcp_client.c
  9. 24
      src/transport_layer/stcp_server.c
  10. 21
      tools/chatgui-android/jni_bridge/android_jni_bridge.c
  11. 4
      tools/chatgui-android/jni_bridge/android_jni_bridge.h
  12. 75
      tools/chatgui/src/accountlist.cpp

26
src/routing_layer/conn_mgr_core.c

@ -531,14 +531,19 @@ static void cm_direct_add_links(struct ETCP_CONN* conn, struct CONN_MGR_ENTRY* e
/* v4 */ /* v4 */
if (db_loaded) { if (db_loaded) {
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) {
if (!(a->protocol & TOPO_PROTO_UDP)) continue;
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets;
while (s) { if (s->local_addr.ss_family == AF_INET) {
struct sockaddr_in sin; memset(&sin,0,sizeof(sin)); sin.sin_family=AF_INET; struct sockaddr_in sin; memset(&sin,0,sizeof(sin)); sin.sin_family=AF_INET;
memcpy(&sin.sin_addr.s_addr,a->addr,4); sin.sin_port=htons(a->port); memcpy(&sin.sin_addr.s_addr,a->addr,4); sin.sin_port=htons(a->port);
struct sockaddr_storage sa; memcpy(&sa,&sin,sizeof(sin)); struct sockaddr_storage sa; memcpy(&sa,&sin,sizeof(sin));
if (a->protocol & TOPO_PROTO_TCP) {
struct ETCP_LINK *tlink = etcp_link_new(conn, NULL, NULL, 0);
if (tlink) { tlink->is_tcp = 1; etcp_tcp_link_start_connect(tlink, &sa, a->port); any = 1; }
}
if (a->protocol & TOPO_PROTO_UDP) {
struct ETCP_SOCKET* s = entry->mgr->instance->etcp_sockets;
while (s) { if (s->local_addr.ss_family == AF_INET) {
if (etcp_link_new(conn,s,&sa,0)) any=1; } s=s->next; } if (etcp_link_new(conn,s,&sa,0)) any=1; } s=s->next; }
} }
}
} else { } else {
uint8_t prio[]={TOPO_ADDR_NAT,TOPO_ADDR_INTERFACE}; uint8_t prio[]={TOPO_ADDR_NAT,TOPO_ADDR_INTERFACE};
for (int pr=0;pr<2;pr++) for (const struct TOPO_ADDR4* a=ni->v4_addrs;a;a=a->next) { for (int pr=0;pr<2;pr++) for (const struct TOPO_ADDR4* a=ni->v4_addrs;a;a=a->next) {
@ -556,11 +561,24 @@ static void cm_direct_add_links(struct ETCP_CONN* conn, struct CONN_MGR_ENTRY* e
} }
/* v6 */ /* v6 */
for (const struct TOPO_ADDR6* a6=ni->v6_addrs;a6;a6=a6->next) { for (const struct TOPO_ADDR6* a6=ni->v6_addrs;a6;a6=a6->next) {
if (!(a6->protocol&TOPO_PROTO_UDP)) continue; int is_ll = (a6->addr[0] == 0xfe && (a6->addr[1] & 0xc0) == 0x80);
if (a6->protocol & TOPO_PROTO_TCP) {
struct sockaddr_in6 sin6; memset(&sin6,0,sizeof(sin6)); sin6.sin6_family=AF_INET6;
memcpy(&sin6.sin6_addr,a6->addr,16); sin6.sin6_port=htons(a6->port);
if (is_ll) { struct ETCP_SOCKET* sv=entry->mgr->instance->etcp_sockets;
while(sv){if(sv->local_addr.ss_family==AF_INET6&&sv->netif_index)
{sin6.sin6_scope_id=sv->netif_index;break;} sv=sv->next;}
}
struct sockaddr_storage sa; memcpy(&sa,&sin6,sizeof(sin6));
struct ETCP_LINK *tlink = etcp_link_new(conn, NULL, NULL, 0);
if (tlink) { tlink->is_tcp = 1; etcp_tcp_link_start_connect(tlink, &sa, a6->port); any = 1; }
}
if (a6->protocol & TOPO_PROTO_UDP) {
uint8_t tc=cm_classify_v6_addr(a6->addr); if(tc==CM_V6_OTH) continue; uint8_t tc=cm_classify_v6_addr(a6->addr); if(tc==CM_V6_OTH) continue;
struct ETCP_SOCKET* s=entry->mgr->instance->etcp_sockets; struct ETCP_SOCKET* s=entry->mgr->instance->etcp_sockets;
while(s){uint8_t sc=cm_sock_v6_classify(s);if(sc==CM_V6_ANY||sc==tc){cm_add_v6_link(conn,a6->addr,a6->port,s);any=1;} s=s->next;} while(s){uint8_t sc=cm_sock_v6_classify(s);if(sc==CM_V6_ANY||sc==tc){cm_add_v6_link(conn,a6->addr,a6->port,s);any=1;} s=s->next;}
} }
}
if (any) return; if (any) return;
node_conn_direct_close(entry->ncd_handle); entry->ncd_handle=NULL; node_conn_direct_close(entry->ncd_handle); entry->ncd_handle=NULL;

14
src/routing_layer/topo_node_sqlite.c

@ -623,8 +623,8 @@ 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 FROM node_addresses" "SELECT address,port,addr_type,socket_id,protocol FROM node_addresses"
" WHERE node_id=? AND family=4 AND protocol=1 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);
while (sqlite3_step(s) == SQLITE_ROW) { while (sqlite3_step(s) == SQLITE_ROW) {
@ -638,8 +638,9 @@ struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* gr
struct TOPO_ADDR4* a4 = memory_pool_alloc(groups->v4_addr_pool); struct TOPO_ADDR4* a4 = memory_pool_alloc(groups->v4_addr_pool);
if (!a4) continue; if (!a4) continue;
memset(a4, 0, sizeof(*a4)); memset(a4, 0, sizeof(*a4));
int proto = sqlite3_column_int(s, 4);
memcpy(a4->addr, addr, 4); a4->port = (uint16_t)port; memcpy(a4->addr, addr, 4); a4->port = (uint16_t)port;
a4->type = type; a4->socket_id = sock_id; a4->protocol = TOPO_PROTO_UDP; a4->type = type; a4->socket_id = sock_id; a4->protocol = (uint8_t)proto;
if (!v4_head) v4_head = v4_tail = a4; if (!v4_head) v4_head = v4_tail = a4;
else { v4_tail->next = a4; v4_tail = a4; } else { v4_tail->next = a4; v4_tail = a4; }
} }
@ -651,8 +652,8 @@ 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 FROM node_addresses" "SELECT address,port,addr_type,socket_id,protocol FROM node_addresses"
" WHERE node_id=? AND family=6 AND protocol=1 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);
while (sqlite3_step(s) == SQLITE_ROW) { while (sqlite3_step(s) == SQLITE_ROW) {
@ -666,8 +667,9 @@ struct TOPO_NODE* topo_node_sqlite_node_load(sqlite3* db, struct TOPO_GROUPS* gr
struct TOPO_ADDR6* a6 = memory_pool_alloc(groups->v6_addr_pool); struct TOPO_ADDR6* a6 = memory_pool_alloc(groups->v6_addr_pool);
if (!a6) continue; if (!a6) continue;
memset(a6, 0, sizeof(*a6)); memset(a6, 0, sizeof(*a6));
int proto6 = sqlite3_column_int(s, 4);
memcpy(a6->addr, addr, 16); a6->port = (uint16_t)port; memcpy(a6->addr, addr, 16); a6->port = (uint16_t)port;
a6->type = type; a6->socket_id = sock_id; a6->protocol = TOPO_PROTO_UDP; a6->type = type; a6->socket_id = sock_id; a6->protocol = (uint8_t)proto6;
if (!v6_head) v6_head = v6_tail = a6; if (!v6_head) v6_head = v6_tail = a6;
else { v6_tail->next = a6; v6_tail = a6; } else { v6_tail->next = a6; v6_tail = a6; }
} }

24
src/transport_layer/auto_socket.c

@ -132,7 +132,7 @@ struct AUTO_SOCKET {
/* ─── forward declarations ─── */ /* ─── forward declarations ─── */
static int create_iface_udp_socket(struct AUTO_SOCKET* as, uint32_t ifindex, const char* ifname, int family, uint8_t type); static int create_iface_udp_socket(struct AUTO_SOCKET* as, uint32_t ifindex, const char* ifname, int family, uint8_t type);
static int create_iface_tcp_socket(struct AUTO_SOCKET* as, uint32_t ifindex, const char* ifname, int family, uint8_t type); static struct stcp_server* create_iface_tcp_socket(struct AUTO_SOCKET* as, uint32_t ifindex, const char* ifname, int family, uint8_t type);
static void remove_iface_sockets(struct AUTO_SOCKET* as, uint32_t ifindex); static void remove_iface_sockets(struct AUTO_SOCKET* as, uint32_t ifindex);
static int scan_and_classify_iface(uint32_t ifindex, const char* ifname, int* out_has_v4, int* out_has_v6, uint8_t* out_v4_type, uint8_t* out_v6_type); static int scan_and_classify_iface(uint32_t ifindex, const char* ifname, int* out_has_v4, int* out_has_v6, uint8_t* out_v4_type, uint8_t* out_v6_type);
static void reconcile_iface(struct AUTO_SOCKET* as, uint32_t ifindex, const char* ifname); static void reconcile_iface(struct AUTO_SOCKET* as, uint32_t ifindex, const char* ifname);
@ -273,7 +273,7 @@ static int create_iface_udp_socket(struct AUTO_SOCKET* as, uint32_t ifindex, con
return -1; return -1;
} }
static int create_iface_tcp_socket(struct AUTO_SOCKET* as, uint32_t ifindex, const char* ifname, int family, uint8_t type) { static struct stcp_server* create_iface_tcp_socket(struct AUTO_SOCKET* as, uint32_t ifindex, const char* ifname, int family, uint8_t type) {
struct UTUN_INSTANCE* inst = as->instance; struct UTUN_INSTANCE* inst = as->instance;
uint16_t saved_port = load_port_from_db(as, ifname, family, AS_PROTO_TCP); uint16_t saved_port = load_port_from_db(as, ifname, family, AS_PROTO_TCP);
@ -296,7 +296,7 @@ static int create_iface_tcp_socket(struct AUTO_SOCKET* as, uint32_t ifindex, con
else else
DEBUG_WARN(DEBUG_CATEGORY_AS, "[as] TCP socket create failed if=%s fam=%d port=%u att=%d err=%d", DEBUG_WARN(DEBUG_CATEGORY_AS, "[as] TCP socket create failed if=%s fam=%d port=%u att=%d err=%d",
ifname, family, port, attempt + 1, socket_get_error()); ifname, family, port, attempt + 1, socket_get_error());
if (socket_get_error() != EADDRINUSE) return -1; if (socket_get_error() != EADDRINUSE) return NULL;
continue; continue;
} }
@ -334,11 +334,11 @@ static int create_iface_tcp_socket(struct AUTO_SOCKET* as, uint32_t ifindex, con
save_port_to_db(as, ifname, family, AS_PROTO_TCP, port); save_port_to_db(as, ifname, family, AS_PROTO_TCP, port);
DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] TCP socket created: if=%s(%u) type=%d port=%u", ifname, ifindex, type, port); DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] TCP socket created: if=%s(%u) type=%d port=%u", ifname, ifindex, type, port);
return 0; return tsrv;
} }
DEBUG_ERROR(DEBUG_CATEGORY_AS, "[as] failed to create TCP socket after %d attempts if=%s fam=%d", max_att, ifname, family); DEBUG_ERROR(DEBUG_CATEGORY_AS, "[as] failed to create TCP socket after %d attempts if=%s fam=%d", max_att, ifname, family);
return -1; return NULL;
} }
int auto_socket_add_interface(struct UTUN_INSTANCE* inst, uint32_t ifindex, int auto_socket_add_interface(struct UTUN_INSTANCE* inst, uint32_t ifindex,
@ -365,9 +365,8 @@ int auto_socket_add_interface(struct UTUN_INSTANCE* inst, uint32_t ifindex,
struct ETCP_SOCKET* s = inst->etcp_sockets; struct ETCP_SOCKET* s = inst->etcp_sockets;
while (s) { if (s->netif_index == ifindex && s->local_addr.ss_family == AF_INET && !ifa->v4_udp) { ifa->v4_udp = s; break; } s = s->next; } while (s) { if (s->netif_index == ifindex && s->local_addr.ss_family == AF_INET && !ifa->v4_udp) { ifa->v4_udp = s; break; } s = s->next; }
} }
if (create_iface_tcp_socket(as, ifindex, ifname, AF_INET, v4_type) == 0) { { struct stcp_server* tsrv = create_iface_tcp_socket(as, ifindex, ifname, AF_INET, v4_type);
added++; if (tsrv) { added++; ifa->v4_tcp = tsrv; } }
}
} }
if (has_v6) { if (has_v6) {
if (create_iface_udp_socket(as, ifindex, ifname, AF_INET6, v6_type) == 0) { if (create_iface_udp_socket(as, ifindex, ifname, AF_INET6, v6_type) == 0) {
@ -375,9 +374,8 @@ int auto_socket_add_interface(struct UTUN_INSTANCE* inst, uint32_t ifindex,
struct ETCP_SOCKET* s = inst->etcp_sockets; struct ETCP_SOCKET* s = inst->etcp_sockets;
while (s) { if (s->netif_index == ifindex && s->local_addr.ss_family == AF_INET6 && !ifa->v6_udp) { ifa->v6_udp = s; break; } s = s->next; } while (s) { if (s->netif_index == ifindex && s->local_addr.ss_family == AF_INET6 && !ifa->v6_udp) { ifa->v6_udp = s; break; } s = s->next; }
} }
if (create_iface_tcp_socket(as, ifindex, ifname, AF_INET6, v6_type) == 0) { { struct stcp_server* tsrv = create_iface_tcp_socket(as, ifindex, ifname, AF_INET6, v6_type);
added++; if (tsrv) { added++; ifa->v6_tcp = tsrv; } }
}
} }
if (added > 0) { if (added > 0) {
@ -713,7 +711,7 @@ static void reconcile_iface(struct AUTO_SOCKET* as, uint32_t ifindex, const char
struct stcp_server* srv = ifa ? ifa->v4_tcp : NULL; struct stcp_server* srv = ifa ? ifa->v4_tcp : NULL;
if (has && !srv) { if (has && !srv) {
if (!ifa) ifa = reconcile_get_ifa(as, ifindex); if (!ifa) ifa = reconcile_get_ifa(as, ifindex);
if (ifa) { create_iface_tcp_socket(as, ifindex, ifname, AF_INET, v4_need_type); ifa->v4_tcp = NULL; /* find below */ changed = 1; } if (ifa) { struct stcp_server* tsrv = create_iface_tcp_socket(as, ifindex, ifname, AF_INET, v4_need_type); ifa->v4_tcp = tsrv; if (tsrv) changed = 1; }
} else if (!has && srv) { } else if (!has && srv) {
DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] v4 TCP removed: %s ifidx=%u", ifname, ifindex); DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] v4 TCP removed: %s ifidx=%u", ifname, ifindex);
{ char buf[IFNAMSIZ]; const char* nm = if_indextoname(ifindex, buf) ? buf : ifname; { char buf[IFNAMSIZ]; const char* nm = if_indextoname(ifindex, buf) ? buf : ifname;
@ -735,7 +733,7 @@ static void reconcile_iface(struct AUTO_SOCKET* as, uint32_t ifindex, const char
struct stcp_server* srv = ifa ? ifa->v6_tcp : NULL; struct stcp_server* srv = ifa ? ifa->v6_tcp : NULL;
if (has && !srv) { if (has && !srv) {
if (!ifa) ifa = reconcile_get_ifa(as, ifindex); if (!ifa) ifa = reconcile_get_ifa(as, ifindex);
if (ifa) { create_iface_tcp_socket(as, ifindex, ifname, AF_INET6, v6_need_type); ifa->v6_tcp = NULL; changed = 1; } if (ifa) { struct stcp_server* tsrv = create_iface_tcp_socket(as, ifindex, ifname, AF_INET6, v6_need_type); ifa->v6_tcp = tsrv; if (tsrv) changed = 1; }
} else if (!has && srv) { } else if (!has && srv) {
DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] v6 TCP removed: %s ifidx=%u", ifname, ifindex); DEBUG_INFO(DEBUG_CATEGORY_AS, "[as] v6 TCP removed: %s ifidx=%u", ifname, ifindex);
{ char buf[IFNAMSIZ]; const char* nm = if_indextoname(ifindex, buf) ? buf : ifname; { char buf[IFNAMSIZ]; const char* nm = if_indextoname(ifindex, buf) ? buf : ifname;

4
src/transport_layer/auto_socket.h

@ -32,6 +32,10 @@ struct ETCP_SOCKET;
int auto_socket_init(struct UTUN_INSTANCE* inst); int auto_socket_init(struct UTUN_INSTANCE* inst);
void auto_socket_destroy(struct UTUN_INSTANCE* inst); void auto_socket_destroy(struct UTUN_INSTANCE* inst);
/* Platform notification: call from any thread when network interfaces change.
* Posts auto_socket_scan_all() to uasync thread. Safe for JNI/ConnectivityManager callbacks. */
void auto_socket_on_network_change(struct UTUN_INSTANCE* inst);
/* ─── Platform-agnostic API: управление сокетами на конкретном интерфейсе ─── */ /* ─── Platform-agnostic API: управление сокетами на конкретном интерфейсе ─── */
/* /*

31
src/transport_layer/etcp_connections.c

@ -44,7 +44,7 @@ static void tcp_link_close_cb(struct stcp_link *sl, int err, void *arg);
void etcp_link_enter_ready_tcp(struct ETCP_LINK *link); void etcp_link_enter_ready_tcp(struct ETCP_LINK *link);
// TCP server: on new incoming connection → create ETCP_LINK + enter ready // TCP server: on new incoming connection → create ETCP_LINK + enter ready
static void tcp_server_on_link(struct stcp_link *link, void *arg) { void tcp_server_on_link(struct stcp_link *link, void *arg) {
struct UTUN_INSTANCE *inst = (struct UTUN_INSTANCE *)arg; struct UTUN_INSTANCE *inst = (struct UTUN_INSTANCE *)arg;
const uint8_t *pubkey = stcp_link_get_peer_pubkey(link); const uint8_t *pubkey = stcp_link_get_peer_pubkey(link);
if (!pubkey) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: no peer pubkey"); return; } if (!pubkey) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "tcp_server_on_link: no peer pubkey"); return; }
@ -180,7 +180,9 @@ static void etcp_link_send_init(struct ETCP_LINK* link, uint8_t reset, uint8_t c
// padding // padding
int wire_ov_init = WIRE_OVERHEAD(link->remote_addr.ss_family); int wire_ov_init = WIRE_OVERHEAD(link->remote_addr.ss_family);
int s = rand() % (link->handshake_maxsize - link->handshake_minsize) + link->handshake_minsize; int pad_range = (int)link->handshake_maxsize - (int)link->handshake_minsize;
if (pad_range <= 0) pad_range = 1;
int s = rand() % pad_range + link->handshake_minsize;
int s_max = (int)(link->mtu) - wire_ov_init; int s_max = (int)(link->mtu) - wire_ov_init;
if (s > s_max) s = s_max; if (s > s_max) s = s_max;
if (s < 0) s = 0; if (s < 0) s = 0;
@ -830,6 +832,15 @@ struct TCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SER
struct sockaddr_in* sin = (struct sockaddr_in*)&server->ip; struct sockaddr_in* sin = (struct sockaddr_in*)&server->ip;
memcpy(&ts->local_addr, sin, sizeof(*sin)); memcpy(&ts->local_addr, sin, sizeof(*sin));
ts->interface_addr = ts->local_addr; ts->interface_addr = ts->local_addr;
if (sin->sin_addr.s_addr == 0 && server->netif_index > 0) {
uint32_t if_ip = get_interface_ip_by_index(server->netif_index);
if (if_ip != 0) {
struct sockaddr_in* if_sin = (struct sockaddr_in*)&ts->interface_addr;
if_sin->sin_family = AF_INET;
if_sin->sin_addr.s_addr = if_ip;
if_sin->sin_port = sin->sin_port;
}
}
if (server->type == CFG_SERVER_TYPE_PUBLIC && sin->sin_addr.s_addr == 0) { if (server->type == CFG_SERVER_TYPE_PUBLIC && sin->sin_addr.s_addr == 0) {
struct sockaddr_storage remote; memset(&remote, 0, sizeof(remote)); struct sockaddr_storage remote; memset(&remote, 0, sizeof(remote));
struct sockaddr_in* rs = (struct sockaddr_in*)&remote; struct sockaddr_in* rs = (struct sockaddr_in*)&remote;
@ -845,6 +856,16 @@ struct TCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SER
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&server->ip; struct sockaddr_in6* sin6 = (struct sockaddr_in6*)&server->ip;
memcpy(&ts->local_addr, sin6, sizeof(*sin6)); memcpy(&ts->local_addr, sin6, sizeof(*sin6));
ts->interface_addr = ts->local_addr; ts->interface_addr = ts->local_addr;
if (memcmp(&sin6->sin6_addr, &in6addr_any, sizeof(struct in6_addr)) == 0 && server->netif_index > 0) {
uint8_t v6addr[16];
int got = get_interface_ipv6_addr_nl(server->netif_index, 1, v6addr);
if (got != 0) got = get_interface_ipv6_addr_nl(server->netif_index, 0, v6addr);
if (got == 0) {
struct sockaddr_in6* if6 = (struct sockaddr_in6*)&ts->interface_addr;
if6->sin6_family = AF_INET6; memcpy(&if6->sin6_addr, v6addr, 16);
if6->sin6_port = sin6->sin6_port;
}
}
if (server->type == CFG_SERVER_TYPE_PUBLIC && memcmp(&sin6->sin6_addr, &in6addr_any, sizeof(struct in6_addr)) == 0) { if (server->type == CFG_SERVER_TYPE_PUBLIC && memcmp(&sin6->sin6_addr, &in6addr_any, sizeof(struct in6_addr)) == 0) {
uint16_t v6if = (server->netif_index > 0) ? server->netif_index : get_default_route_netif_index(AF_INET6); uint16_t v6if = (server->netif_index > 0) ? server->netif_index : get_default_route_netif_index(AF_INET6);
if (v6if > 0) { if (v6if > 0) {
@ -905,7 +926,7 @@ struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn
link->is_tcp = (uint8_t)is_tcp; link->is_tcp = (uint8_t)is_tcp;
int mtu; int mtu;
mtu = conn ? conn->mtu : STCP_MAX_MSG_SIZE; mtu = conn ? conn->mtu : STCP_MAX_MSG_SIZE;
if (is_tcp) { mtu = STCP_MAX_MSG_SIZE; link->mtu_local = mtu; link->mtu = mtu; link->inflight_lim_bytes = mtu * 4; } if (is_tcp) { mtu = STCP_MAX_MSG_SIZE; link->mtu_local = mtu; link->mtu = mtu; link->inflight_lim_bytes = mtu * 4; link->handshake_minsize = 100; link->handshake_maxsize = mtu; }
else { if (mtu == 0) mtu = 1500; if (mtu > PACKET_DATA_MAX_MTU) mtu = PACKET_DATA_MAX_MTU; link->mtu_local = mtu; link->mtu = mtu; link->inflight_lim_bytes = mtu * 4; link->handshake_minsize = 100; link->handshake_maxsize = mtu; } else { if (mtu == 0) mtu = 1500; if (mtu > PACKET_DATA_MAX_MTU) mtu = PACKET_DATA_MAX_MTU; link->mtu_local = mtu; link->mtu = mtu; link->inflight_lim_bytes = mtu * 4; link->handshake_minsize = 100; link->handshake_maxsize = mtu; }
/* mtu init moved above */ /* mtu init moved above */
etcp_update_mtu(etcp); etcp_update_mtu(etcp);
@ -1603,7 +1624,9 @@ static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pk
// padding // padding
int wire_ov = WIRE_OVERHEAD(link->remote_addr.ss_family); int wire_ov = WIRE_OVERHEAD(link->remote_addr.ss_family);
int max_data = link->mtu - wire_ov; int max_data = link->mtu - wire_ov;
int s = rand() % (link->handshake_maxsize - link->handshake_minsize) + link->handshake_minsize; int pad_range = (int)link->handshake_maxsize - (int)link->handshake_minsize;
if (pad_range <= 0) pad_range = 1;
int s = rand() % pad_range + 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;

3
src/transport_layer/etcp_connections.h

@ -342,6 +342,9 @@ struct TCP_SOCKET {
struct TCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SERVER* server); struct TCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SERVER* server);
void tcp_socket_remove(struct TCP_SOCKET* sock); void tcp_socket_remove(struct TCP_SOCKET* sock);
struct stcp_link;
void tcp_server_on_link(struct stcp_link *link, void *arg);
// connection functions // connection functions
// создает новый канал связи для etcp подключения (ETCP_CONN) // создает новый канал связи для etcp подключения (ETCP_CONN)
struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn, struct sockaddr_storage* remote_addr, uint8_t is_server); struct ETCP_LINK* etcp_link_new(struct ETCP_CONN* etcp, struct ETCP_SOCKET* conn, struct sockaddr_storage* remote_addr, uint8_t is_server);

2
src/transport_layer/stcp.c

@ -27,7 +27,7 @@ void stcp_conn_set_on_close(struct stcp_conn *c, void (*cb)(struct stcp_conn *co
void stcp_conn_free(struct stcp_conn *c) { void stcp_conn_free(struct stcp_conn *c) {
if (!c) return; if (!c) return;
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_conn_free: c=%p sock=%d sock_id=%p recv_buf=%p state=%d allocated=%d", DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_conn_free: c=%p sock=%d sock_id=%p recv_buf=%p state=%d allocated=%d",
(void*)c, (int)c->sock, (void*)c->socket_id, (void*)c->recv_buf, (int)c->state, (int)c->allocated); (void*)c, (int)c->sock, (void*)c->socket_id, (void*)c->recv_buf, (int)c->state, (int)c->allocated);
if (c->socket_id) { uasync_remove_socket_t(c->ua, c->sock); c->socket_id = NULL; } if (c->socket_id) { uasync_remove_socket_t(c->ua, c->sock); c->socket_id = NULL; }
if (c->sock != SOCKET_INVALID) { socket_close_wrapper(c->sock); c->sock = SOCKET_INVALID; } if (c->sock != SOCKET_INVALID) { socket_close_wrapper(c->sock); c->sock = SOCKET_INVALID; }

24
src/transport_layer/stcp_client.c

@ -38,7 +38,7 @@ static int client_derive_session(struct stcp_conn *c, const uint8_t *peer_pubkey
if (sc_set_peer_public_key(&sc, peer_pubkey, SC_PEER_PUBKEY_BIN) != SC_OK) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "client ECDH failed"); return -1; } if (sc_set_peer_public_key(&sc, peer_pubkey, SC_PEER_PUBKEY_BIN) != SC_OK) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "client ECDH failed"); return -1; }
memcpy(c->session_key, sc.session_key, SC_SESSION_KEY_SIZE); memcpy(c->session_key, sc.session_key, SC_SESSION_KEY_SIZE);
memcpy(c->peer_pubkey, peer_pubkey, SC_PUBKEY_SIZE); c->peer_pubkey_set = 1; memcpy(c->peer_pubkey, peer_pubkey, SC_PUBKEY_SIZE); c->peer_pubkey_set = 1;
log_dump(DEBUG_LEVEL_ERROR, DEBUG_CATEGORY_DEBUG, "stcp_client session_key", c->session_key, 16); log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_CRYPTO, "stcp_client session_key", c->session_key, 16);
if (sc_stream_init(&sc, &c->stream_send, STCP_STREAM_CLIENT_SEND) != SC_OK) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "client stream_send init failed"); return -1; } if (sc_stream_init(&sc, &c->stream_send, STCP_STREAM_CLIENT_SEND) != SC_OK) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "client stream_send init failed"); return -1; }
if (sc_stream_init(&sc, &c->stream_recv, STCP_STREAM_SERVER_SEND) != SC_OK) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "client stream_recv init failed"); return -1; } if (sc_stream_init(&sc, &c->stream_recv, STCP_STREAM_SERVER_SEND) != SC_OK) { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "client stream_recv init failed"); return -1; }
return 0; return 0;
@ -69,7 +69,7 @@ static void client_send_handshake(struct stcp_conn *c, const uint8_t *server_pub
} }
static void process_server_response(struct stcp_conn *c) { static void process_server_response(struct stcp_conn *c) {
log_dump(DEBUG_LEVEL_ERROR, DEBUG_CATEGORY_DEBUG, "stcp_client process_srv_resp recv_buf", c->recv_buf, c->recv_buf_len); log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_ETCP, "stcp_client process_srv_resp recv_buf", c->recv_buf, c->recv_buf_len);
if (!c->hs_key_processed) { if (!c->hs_key_processed) {
const uint8_t *salt = c->recv_buf; const uint8_t *salt = c->recv_buf;
const uint8_t *enc_pubkey = salt + SC_PUBKEY_ENC_SALT_SIZE; const uint8_t *enc_pubkey = salt + SC_PUBKEY_ENC_SALT_SIZE;
@ -83,10 +83,10 @@ static void process_server_response(struct stcp_conn *c) {
} }
uint8_t enc_hs[STCP_HS_ENC_SERVER]; uint8_t enc_hs[STCP_HS_ENC_SERVER];
memcpy(enc_hs, c->recv_buf + SC_PUBKEY_ENC_SIZE, STCP_HS_ENC_SERVER); memcpy(enc_hs, c->recv_buf + SC_PUBKEY_ENC_SIZE, STCP_HS_ENC_SERVER);
log_dump(DEBUG_LEVEL_ERROR, DEBUG_CATEGORY_DEBUG, "stcp_client enc_hs BEFORE xor", enc_hs, STCP_HS_ENC_SERVER); log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_CRYPTO, "stcp_client enc_hs BEFORE xor", enc_hs, STCP_HS_ENC_SERVER);
size_t hs_data_len; size_t hs_data_len;
if (stcp_frame_decrypt(enc_hs, STCP_HS_ENC_SERVER, &c->stream_recv, &hs_data_len)) { client_do_close(c, 3); return; } if (stcp_frame_decrypt(enc_hs, STCP_HS_ENC_SERVER, &c->stream_recv, &hs_data_len)) { client_do_close(c, 3); return; }
log_dump(DEBUG_LEVEL_ERROR, DEBUG_CATEGORY_DEBUG, "stcp_client enc_hs AFTER xor", enc_hs, STCP_HS_ENC_SERVER); log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_CRYPTO, "stcp_client enc_hs AFTER xor", enc_hs, STCP_HS_ENC_SERVER);
memcpy(c->peer_ed25519_pubkey, enc_hs, SC_PUBKEY_SIZE); c->peer_ed25519_set = 1; memcpy(c->peer_ed25519_pubkey, enc_hs, SC_PUBKEY_SIZE); c->peer_ed25519_set = 1;
uint8_t status = enc_hs[32]; uint8_t status = enc_hs[32];
uint16_t padding_size = (uint16_t)enc_hs[33] | ((uint16_t)enc_hs[34] << 8); uint16_t padding_size = (uint16_t)enc_hs[33] | ((uint16_t)enc_hs[34] << 8);
@ -106,7 +106,7 @@ static void finish_server_response(struct stcp_conn *c) {
} }
static void stcp_conn_process_recv(struct stcp_conn *c) { static void stcp_conn_process_recv(struct stcp_conn *c) {
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_client: process_recv entry state=%d sock=%d recv_buf=%p len=%zu cap=%zu", DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "stcp_client: process_recv entry state=%d sock=%d recv_buf=%p len=%zu cap=%zu",
c->state, (int)c->sock, (void*)c->recv_buf, c->recv_buf_len, c->recv_buf_cap); c->state, (int)c->sock, (void*)c->recv_buf, c->recv_buf_len, c->recv_buf_cap);
if (!c->recv_buf && c->recv_buf_len > 0) { if (!c->recv_buf && c->recv_buf_len > 0) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_client: process_recv NULL recv_buf with len=%zu — closing", c->recv_buf_len); DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_client: process_recv NULL recv_buf with len=%zu — closing", c->recv_buf_len);
@ -136,8 +136,6 @@ static void stcp_conn_process_recv(struct stcp_conn *c) {
if (e) { e->dgram = u_malloc(data_len); if (e->dgram) { if (data_len) memcpy(e->dgram, enc_data, data_len); e->len = (uint16_t)data_len; queue_data_put(c->rx_queue, e); } else { queue_entry_free(e); } } if (e) { e->dgram = u_malloc(data_len); if (e->dgram) { if (data_len) memcpy(e->dgram, enc_data, data_len); e->len = (uint16_t)data_len; queue_data_put(c->rx_queue, e); } else { queue_entry_free(e); } }
if (c->state != STCP_STATE_DATA) return; if (c->state != STCP_STATE_DATA) return;
} }
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_client: memmove recv_buf=%p src=%p(+%zu) len=%zu (total=%zu recv_buf_len=%zu)",
(void*)c->recv_buf, (void*)(c->recv_buf + total), total, c->recv_buf_len - total, total, c->recv_buf_len);
if ((uintptr_t)c->recv_buf < 4096) { if ((uintptr_t)c->recv_buf < 4096) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_client: suspicious recv_buf=%p (addr < 4K) — closing", (void*)c->recv_buf); DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_client: suspicious recv_buf=%p (addr < 4K) — closing", (void*)c->recv_buf);
client_do_close(c, EFAULT); return; client_do_close(c, EFAULT); return;
@ -154,10 +152,10 @@ static void stcp_conn_process_recv(struct stcp_conn *c) {
static void client_conn_read_cb(socket_t sock, void *arg) { static void client_conn_read_cb(socket_t sock, void *arg) {
struct stcp_conn *c = (struct stcp_conn *)arg; struct stcp_conn *c = (struct stcp_conn *)arg;
if (c->state == STCP_STATE_CLOSED || c->state == STCP_STATE_ERROR) { if (c->state == STCP_STATE_CLOSED || c->state == STCP_STATE_ERROR) {
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_client: read_cb SKIP state=%d sock=%d c=%p recv_buf=%p", c->state, (int)sock, (void*)c, (void*)c->recv_buf); DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_client: read_cb SKIP state=%d sock=%d c=%p recv_buf=%p", c->state, (int)sock, (void*)c, (void*)c->recv_buf);
return; return;
} }
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_client: read_cb state=%d sock=%d c=%p recv_buf=%p len=%zu cap=%zu", DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "stcp_client: read_cb state=%d sock=%d c=%p recv_buf=%p len=%zu cap=%zu",
c->state, (int)sock, (void*)c, (void*)c->recv_buf, c->recv_buf_len, c->recv_buf_cap); c->state, (int)sock, (void*)c, (void*)c->recv_buf, c->recv_buf_len, c->recv_buf_cap);
if (!c->recv_buf) { c->recv_buf_cap = STCP_RECV_BUF_INIT; c->recv_buf = u_malloc(c->recv_buf_cap); if (!c->recv_buf) { client_do_close(c, ENOMEM); return; } } if (!c->recv_buf) { c->recv_buf_cap = STCP_RECV_BUF_INIT; c->recv_buf = u_malloc(c->recv_buf_cap); if (!c->recv_buf) { client_do_close(c, ENOMEM); return; } }
if (c->recv_buf_len + 4096 > c->recv_buf_cap) { if (c->recv_buf_len + 4096 > c->recv_buf_cap) {
@ -208,14 +206,14 @@ static void client_do_close(struct stcp_conn *c, int err) {
int prev = c->state; int prev = c->state;
c->state = STCP_STATE_CLOSED; c->state = STCP_STATE_CLOSED;
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_client: closed is_server=%d err=%d prev_state=%d", c->is_server, err, prev); DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_client: closed is_server=%d err=%d prev_state=%d", c->is_server, err, prev);
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_client: do_close sock=%d sock_id=%p recv_buf=%p len=%zu cap=%zu send_buf=%p on_close=%p", DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_client: do_close sock=%d sock_id=%p recv_buf=%p len=%zu cap=%zu send_buf=%p on_close=%p",
(int)c->sock, (void*)c->socket_id, (void*)c->recv_buf, c->recv_buf_len, c->recv_buf_cap, (void*)c->send_buf, (void*)c->on_close); (int)c->sock, (void*)c->socket_id, (void*)c->recv_buf, c->recv_buf_len, c->recv_buf_cap, (void*)c->send_buf, (void*)c->on_close);
if (c->socket_id) { uasync_remove_socket_t(c->ua, c->sock); c->socket_id = NULL; } if (c->socket_id) { uasync_remove_socket_t(c->ua, c->sock); c->socket_id = NULL; }
if (c->sock != SOCKET_INVALID) { socket_close_wrapper(c->sock); c->sock = SOCKET_INVALID; } if (c->sock != SOCKET_INVALID) { socket_close_wrapper(c->sock); c->sock = SOCKET_INVALID; }
if (c->recv_buf) { void *p = c->recv_buf; u_free(c->recv_buf); c->recv_buf = NULL; c->recv_buf_len = 0; c->recv_buf_cap = 0; DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_client: do_close u_free recv_buf=%p", p); } if (c->recv_buf) { void *p = c->recv_buf; u_free(c->recv_buf); c->recv_buf = NULL; c->recv_buf_len = 0; c->recv_buf_cap = 0; DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_client: do_close u_free recv_buf=%p", p); }
if (c->send_buf) { void *p = c->send_buf; u_free(c->send_buf); c->send_buf = NULL; c->send_len = 0; DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_client: do_close u_free send_buf=%p", p); } if (c->send_buf) { void *p = c->send_buf; u_free(c->send_buf); c->send_buf = NULL; c->send_len = 0; DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_client: do_close u_free send_buf=%p", p); }
stcp_pending_clear(c); stcp_pending_clear(c);
if (c->on_close) { void (*cb)(struct stcp_conn*, int, void*) = c->on_close; c->on_close = NULL; DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_client: do_close calling on_close=%p", (void*)cb); cb(c, err, c->close_arg); DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_client: do_close on_close returned"); } if (c->on_close) { void (*cb)(struct stcp_conn*, int, void*) = c->on_close; c->on_close = NULL; DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_client: do_close calling on_close=%p", (void*)cb); cb(c, err, c->close_arg); DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_client: do_close on_close returned"); }
} }
struct stcp_client *stcp_client_connect(struct UASYNC *ua, const char *addr, uint16_t port, struct stcp_client *stcp_client_connect(struct UASYNC *ua, const char *addr, uint16_t port,

24
src/transport_layer/stcp_server.c

@ -44,7 +44,7 @@ static int derive_session_and_streams(struct stcp_conn *c, const uint8_t *peer_p
return -1; return -1;
} }
memcpy(c->session_key, sc.session_key, SC_SESSION_KEY_SIZE); memcpy(c->session_key, sc.session_key, SC_SESSION_KEY_SIZE);
log_dump(DEBUG_LEVEL_ERROR, DEBUG_CATEGORY_DEBUG, "stcp_server session_key", c->session_key, 16); log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_CRYPTO, "stcp_server session_key", c->session_key, 16);
if (sc_stream_init(&sc, &c->stream_send, STCP_STREAM_SERVER_SEND) != SC_OK) { if (sc_stream_init(&sc, &c->stream_send, STCP_STREAM_SERVER_SEND) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stream_send init failed"); DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stream_send init failed");
return -1; return -1;
@ -101,17 +101,17 @@ static void finish_client_handshake(struct stcp_conn *c) {
uint8_t *enc_dst = resp + SC_PUBKEY_ENC_SIZE; uint8_t *enc_dst = resp + SC_PUBKEY_ENC_SIZE;
memcpy(enc_dst, plain_hs, 35); memcpy(enc_dst, plain_hs, 35);
enc_dst[35] = (uint8_t)(crc >> 0); enc_dst[36] = (uint8_t)(crc >> 8); enc_dst[37] = (uint8_t)(crc >> 16); enc_dst[38] = (uint8_t)(crc >> 24); enc_dst[35] = (uint8_t)(crc >> 0); enc_dst[36] = (uint8_t)(crc >> 8); enc_dst[37] = (uint8_t)(crc >> 16); enc_dst[38] = (uint8_t)(crc >> 24);
log_dump(DEBUG_LEVEL_ERROR, DEBUG_CATEGORY_DEBUG, "stcp_server hs_resp BEFORE xor", enc_dst, STCP_HS_ENC_SERVER); log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_CRYPTO, "stcp_server hs_resp BEFORE xor", enc_dst, STCP_HS_ENC_SERVER);
if (sc_stream_xor(&c->stream_send, enc_dst, STCP_HS_ENC_SERVER) != SC_OK) { if (sc_stream_xor(&c->stream_send, enc_dst, STCP_HS_ENC_SERVER) != SC_OK) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "encrypt failed"); DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "encrypt failed");
u_free(resp); stcp_conn_do_close(c, 3); return; u_free(resp); stcp_conn_do_close(c, 3); return;
} }
log_dump(DEBUG_LEVEL_ERROR, DEBUG_CATEGORY_DEBUG, "stcp_server hs_resp AFTER xor", enc_dst, STCP_HS_ENC_SERVER); log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_CRYPTO, "stcp_server hs_resp AFTER xor", enc_dst, STCP_HS_ENC_SERVER);
for (int i = 0; i < padding; i++) resp[SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_SERVER + i] = (uint8_t)(salt2[0] ^ i); for (int i = 0; i < padding; i++) resp[SC_PUBKEY_ENC_SIZE + STCP_HS_ENC_SERVER + i] = (uint8_t)(salt2[0] ^ i);
c->state = STCP_STATE_DATA; c->state = STCP_STATE_DATA;
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_server: handshake OK, entering DATA state"); DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_server: handshake OK, entering DATA state");
log_dump(DEBUG_LEVEL_ERROR, DEBUG_CATEGORY_DEBUG, "stcp_server FULL RESP", resp, total_resp); log_dump(DEBUG_LEVEL_DEBUG, DEBUG_CATEGORY_ETCP, "stcp_server FULL RESP", resp, total_resp);
int r = stcp_try_send(c, resp, total_resp); int r = stcp_try_send(c, resp, total_resp);
if (r < 0) { u_free(resp); stcp_conn_do_close(c, 3); return; } if (r < 0) { u_free(resp); stcp_conn_do_close(c, 3); return; }
if (c->on_ready) c->on_ready(c, c->ready_arg); if (c->on_ready) c->on_ready(c, c->ready_arg);
@ -120,10 +120,10 @@ static void finish_client_handshake(struct stcp_conn *c) {
static void server_conn_read_cb(socket_t sock, void *arg) { static void server_conn_read_cb(socket_t sock, void *arg) {
struct stcp_conn *c = (struct stcp_conn *)arg; struct stcp_conn *c = (struct stcp_conn *)arg;
if (c->state == STCP_STATE_CLOSED || c->state == STCP_STATE_ERROR) { if (c->state == STCP_STATE_CLOSED || c->state == STCP_STATE_ERROR) {
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_server: read_cb SKIP state=%d sock=%d c=%p recv_buf=%p", c->state, (int)sock, (void*)c, (void*)c->recv_buf); DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_server: read_cb SKIP state=%d sock=%d c=%p recv_buf=%p", c->state, (int)sock, (void*)c, (void*)c->recv_buf);
return; return;
} }
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_server: read_cb state=%d sock=%d c=%p recv_buf=%p len=%zu cap=%zu", DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "stcp_server: read_cb state=%d sock=%d c=%p recv_buf=%p len=%zu cap=%zu",
c->state, (int)sock, (void*)c, (void*)c->recv_buf, c->recv_buf_len, c->recv_buf_cap); c->state, (int)sock, (void*)c, (void*)c->recv_buf, c->recv_buf_len, c->recv_buf_cap);
if (c->recv_buf_cap == 0) { if (c->recv_buf_cap == 0) {
@ -152,7 +152,7 @@ static void server_conn_read_cb(socket_t sock, void *arg) {
} }
static void stcp_conn_process_recv(struct stcp_conn *c) { static void stcp_conn_process_recv(struct stcp_conn *c) {
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_server: process_recv entry state=%d sock=%d recv_buf=%p len=%zu cap=%zu", DEBUG_TRACE(DEBUG_CATEGORY_ETCP, "stcp_server: process_recv entry state=%d sock=%d recv_buf=%p len=%zu cap=%zu",
c->state, (int)c->sock, (void*)c->recv_buf, c->recv_buf_len, c->recv_buf_cap); c->state, (int)c->sock, (void*)c->recv_buf, c->recv_buf_len, c->recv_buf_cap);
if (!c->recv_buf && c->recv_buf_len > 0) { if (!c->recv_buf && c->recv_buf_len > 0) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_server: process_recv NULL recv_buf with len=%zu — closing", c->recv_buf_len); DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_server: process_recv NULL recv_buf with len=%zu — closing", c->recv_buf_len);
@ -191,8 +191,6 @@ static void stcp_conn_process_recv(struct stcp_conn *c) {
else { queue_entry_free(e); DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "rx malloc(%zu) failed", data_len); } else { queue_entry_free(e); DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "rx malloc(%zu) failed", data_len); }
} else { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "queue_entry_new failed"); } } else { DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "queue_entry_new failed"); }
} }
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_server: memmove recv_buf=%p src=%p(+%zu) len=%zu (total=%zu recv_buf_len=%zu)",
(void*)c->recv_buf, (void*)(c->recv_buf + total), total, c->recv_buf_len - total, total, c->recv_buf_len);
if ((uintptr_t)c->recv_buf < 4096) { if ((uintptr_t)c->recv_buf < 4096) {
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_server: suspicious recv_buf=%p (addr < 4K) — closing", (void*)c->recv_buf); DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "stcp_server: suspicious recv_buf=%p (addr < 4K) — closing", (void*)c->recv_buf);
stcp_conn_do_close(c, EFAULT); return; stcp_conn_do_close(c, EFAULT); return;
@ -228,13 +226,13 @@ static void stcp_conn_do_close(struct stcp_conn *c, int err) {
c->state = STCP_STATE_CLOSED; c->state = STCP_STATE_CLOSED;
if (c->socket_id) { uasync_remove_socket_t(c->ua, c->sock); c->socket_id = NULL; } if (c->socket_id) { uasync_remove_socket_t(c->ua, c->sock); c->socket_id = NULL; }
if (c->sock != SOCKET_INVALID) { socket_close_wrapper(c->sock); c->sock = SOCKET_INVALID; } if (c->sock != SOCKET_INVALID) { socket_close_wrapper(c->sock); c->sock = SOCKET_INVALID; }
if (c->recv_buf) { void *p = c->recv_buf; u_free(c->recv_buf); c->recv_buf = NULL; c->recv_buf_len = 0; c->recv_buf_cap = 0; DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_server: do_close u_free recv_buf=%p", p); } if (c->recv_buf) { void *p = c->recv_buf; u_free(c->recv_buf); c->recv_buf = NULL; c->recv_buf_len = 0; c->recv_buf_cap = 0; DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_server: do_close u_free recv_buf=%p", p); }
if (c->send_buf) { void *p = c->send_buf; u_free(c->send_buf); c->send_buf = NULL; c->send_len = 0; DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_server: do_close u_free send_buf=%p", p); } if (c->send_buf) { void *p = c->send_buf; u_free(c->send_buf); c->send_buf = NULL; c->send_len = 0; DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_server: do_close u_free send_buf=%p", p); }
stcp_pending_clear(c); stcp_pending_clear(c);
DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_conn closed is_server=%d prev_state=%d err=%d sock=%d", c->is_server, prev, err, (int)c->sock); DEBUG_INFO(DEBUG_CATEGORY_ETCP, "stcp_conn closed is_server=%d prev_state=%d err=%d sock=%d", c->is_server, prev, err, (int)c->sock);
DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_server: do_close sock=%d sock_id=%p recv_buf was=%p on_close=%p", DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_server: do_close sock=%d sock_id=%p recv_buf was=%p on_close=%p",
(int)c->sock, (void*)c->socket_id, (void*)c->recv_buf, (void*)c->on_close); (int)c->sock, (void*)c->socket_id, (void*)c->recv_buf, (void*)c->on_close);
if (c->on_close) { void (*cb)(struct stcp_conn*, int, void*) = c->on_close; c->on_close = NULL; DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_server: do_close calling on_close=%p", (void*)cb); cb(c, err, c->close_arg); DEBUG_DEBUG(DEBUG_CATEGORY_DEBUG, "stcp_server: do_close on_close returned"); } if (c->on_close) { void (*cb)(struct stcp_conn*, int, void*) = c->on_close; c->on_close = NULL; DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_server: do_close calling on_close=%p", (void*)cb); cb(c, err, c->close_arg); DEBUG_DEBUG(DEBUG_CATEGORY_ETCP, "stcp_server: do_close on_close returned"); }
else if (prev == STCP_STATE_HS_SERVER_WAIT) { sc_stream_cleanup(&c->stream_send); sc_stream_cleanup(&c->stream_recv); if (c->allocated) uasync_call_soon(c->ua, c, stcp_conn_deferred_free); } else if (prev == STCP_STATE_HS_SERVER_WAIT) { sc_stream_cleanup(&c->stream_send); sc_stream_cleanup(&c->stream_recv); if (c->allocated) uasync_call_soon(c->ua, c, stcp_conn_deferred_free); }
} }

21
tools/chatgui-android/jni_bridge/android_jni_bridge.c

@ -22,6 +22,7 @@
#include "../../../src/utun_instance.h" #include "../../../src/utun_instance.h"
#include "../../../src/transport_layer/etcp.h" #include "../../../src/transport_layer/etcp.h"
#include "../../../src/transport_layer/etcp_connections.h" #include "../../../src/transport_layer/etcp_connections.h"
#include "../../../src/transport_layer/auto_socket.h"
#include "../../../src/transport_layer/secure_channel.h" #include "../../../src/transport_layer/secure_channel.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -1060,6 +1061,8 @@ char* utun_bridge_get_local_sockets_json(void) {
json[0] = '['; json[0] = '[';
int first = 1; int first = 1;
bridge_log(BLEV_INFO, "getLocalSockets: tcp_sockets=%p etcp_sockets=%p conns=%d links=%d",
(void*)inst->tcp_sockets, (void*)inst->etcp_sockets, active_conns, active_links);
/* TCP sockets */ /* TCP sockets */
{ struct TCP_SOCKET* ts = inst->tcp_sockets; { struct TCP_SOCKET* ts = inst->tcp_sockets;
while (ts) { while (ts) {
@ -1074,7 +1077,7 @@ char* utun_bridge_get_local_sockets_json(void) {
port = ntohs(sin6->sin6_port); port = ntohs(sin6->sin6_port);
inet_ntop(AF_INET6, &sin6->sin6_addr, ip_str, sizeof(ip_str)); inet_ntop(AF_INET6, &sin6->sin6_addr, ip_str, sizeof(ip_str));
} }
int state = active_conns > 0 ? 2 : 0; int state = 2; /* bound and listening */
const char* sep = first ? "" : ","; first = 0; const char* sep = first ? "" : ","; first = 0;
size_t needed = snprintf(NULL, 0, "%s{\"si\":%u,\"nm\":\"%s\",\"ad\":\"%s\",\"po\":%d,\"pt\":\"TCP\",\"st\":%d,\"lk\":%d}", size_t needed = snprintf(NULL, 0, "%s{\"si\":%u,\"nm\":\"%s\",\"ad\":\"%s\",\"po\":%d,\"pt\":\"TCP\",\"st\":%d,\"lk\":%d}",
sep, ts->sock_id, ts->name, ip_str, port, state, active_links); sep, ts->sock_id, ts->name, ip_str, port, state, active_links);
@ -1101,7 +1104,7 @@ char* utun_bridge_get_local_sockets_json(void) {
inet_ntop(AF_INET6, &sin6->sin6_addr, ip_str, sizeof(ip_str)); inet_ntop(AF_INET6, &sin6->sin6_addr, ip_str, sizeof(ip_str));
} }
int lk = es->links_queue ? queue_entry_count(es->links_queue) : 0; int lk = es->links_queue ? queue_entry_count(es->links_queue) : 0;
int state = lk > 0 ? 2 : 0; int state = 2; /* bound and listening */
const char* sep = first ? "" : ","; first = 0; const char* sep = first ? "" : ","; first = 0;
size_t needed = snprintf(NULL, 0, "%s{\"si\":%u,\"nm\":\"%s\",\"ad\":\"%s\",\"po\":%d,\"pt\":\"UDP\",\"st\":%d,\"lk\":%d}", size_t needed = snprintf(NULL, 0, "%s{\"si\":%u,\"nm\":\"%s\",\"ad\":\"%s\",\"po\":%d,\"pt\":\"UDP\",\"st\":%d,\"lk\":%d}",
sep, es->sock_id, es->name, ip_str, port, state, lk); sep, es->sock_id, es->name, ip_str, port, state, lk);
@ -1117,6 +1120,12 @@ char* utun_bridge_get_local_sockets_json(void) {
return json; return json;
} }
void utun_bridge_on_network_change(void) {
if (!g_cc.inst) return;
auto_socket_on_network_change(g_cc.inst);
bridge_log(BLEV_DEBUG, "network change notified to auto_socket");
}
void utun_bridge_restart(const char* config_text) { void utun_bridge_restart(const char* config_text) {
bridge_log(BLEV_INFO, "bridge restart: posting to instance"); bridge_log(BLEV_INFO, "bridge restart: posting to instance");
#ifdef __ANDROID__ #ifdef __ANDROID__
@ -1914,4 +1923,12 @@ JNIEXPORT jstring JNICALL Java_com_utun_chat_data_NativeLib_nativeGetLocalSocket
return result; return result;
} }
/* ── Network change notification ── */
JNIEXPORT void JNICALL Java_com_utun_chat_data_NativeLib_nativeOnNetworkChanged(
JNIEnv* env, jobject thiz) {
(void)env; (void)thiz;
utun_bridge_on_network_change();
}
#endif /* __ANDROID__ */ #endif /* __ANDROID__ */

4
tools/chatgui-android/jni_bridge/android_jni_bridge.h

@ -129,6 +129,10 @@ char* utun_bridge_get_member_links_json(uint64_t node_id);
char* utun_bridge_get_local_sockets_json(void); char* utun_bridge_get_local_sockets_json(void);
/* ── Network change notification (ConnectivityManager → auto_socket) ── */
void utun_bridge_on_network_change(void);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

75
tools/chatgui/src/accountlist.cpp

@ -9,6 +9,7 @@
#include <QLabel> #include <QLabel>
#include <QDateTime> #include <QDateTime>
#include <QFont> #include <QFont>
#include <QSet>
#include "../../../lib/platform_compat.h" #include "../../../lib/platform_compat.h"
extern "C" { extern "C" {
@ -16,6 +17,8 @@ extern "C" {
#include "etcp.h" #include "etcp.h"
#include "etcp_connections.h" #include "etcp_connections.h"
#include "../lib/socket_compat.h" #include "../lib/socket_compat.h"
#include "../lib/ll_queue.h"
#include "stcp_link.h"
} }
QString AccountList::addrStr(const void* addr, int family) { QString AccountList::addrStr(const void* addr, int family) {
@ -211,6 +214,30 @@ void AccountList::updateDetailDisplay() {
struct ETCP_CONN* conn = nullptr; struct ETCP_CONN* conn = nullptr;
if (m_inst) conn = instance_find_conn(m_inst, m_detailNodeId); if (m_inst) conn = instance_find_conn(m_inst, m_detailNodeId);
bool isSelf = m_db ? (m_detailNodeId == m_db->myNodeId()) : false;
QSet<struct ETCP_LINK*> matchedLinks;
/* Count active TCP connections for own node (shared across all TCP sockets) */
int ownTcpActiveLinks = 0;
if (isSelf && m_inst) {
if (m_inst->connections) {
for (struct ll_entry* e = m_inst->connections->head; e; e = e->next) {
struct conn_queue_entry* ce = (struct conn_queue_entry*)e->data;
if (ce && ce->conn && ce->conn->initialized) {
for (struct ETCP_LINK* lk = ce->conn->links; lk; lk = lk->next) {
if (lk->is_tcp) { ownTcpActiveLinks++; break; }
}
}
}
}
if (m_inst->tcp_connections) {
for (struct ll_entry* e = m_inst->tcp_connections->head; e; e = e->next) {
struct tcp_conn_entry* te = (struct tcp_conn_entry*)e->data;
if (te && te->etcp_conn && te->etcp_conn->initialized) ownTcpActiveLinks++;
}
}
}
for (const auto& a : m_detailAddrs) { for (const auto& a : m_detailAddrs) {
QString proto; QString proto;
switch (a.protocol) { case 1: proto = "UDP"; break; case 2: proto = "TCP"; break; default: proto = "UDP/TCP"; break; } switch (a.protocol) { case 1: proto = "UDP"; break; case 2: proto = "TCP"; break; default: proto = "UDP/TCP"; break; }
@ -231,6 +258,7 @@ void AccountList::updateDetailDisplay() {
} }
if (lfm == a.family && lpo == (uint16_t)a.port && lip == addrStr(a.addr.constData(), a.family)) { if (lfm == a.family && lpo == (uint16_t)a.port && lip == addrStr(a.addr.constData(), a.family)) {
linkColor = (lk->link_state == 3 && lk->link_status == 1) ? "#4CAF50" : "#E53935"; linkColor = (lk->link_state == 3 && lk->link_status == 1) ? "#4CAF50" : "#E53935";
matchedLinks.insert(lk);
break; break;
} }
} }
@ -243,8 +271,51 @@ void AccountList::updateDetailDisplay() {
} }
} }
} }
lines.append(QString("<span style='color:%1;'>●</span> %2:%3:%4")
.arg(linkColor, proto, addrStr(a.addr.constData(), a.family)).arg(a.port)); QString prefix;
if (isSelf && m_inst) {
int linkCount = 0;
if (a.protocol == 1) {
for (struct ETCP_SOCKET* sock = m_inst->etcp_sockets; sock; sock = sock->next) {
uint16_t sp = 0;
const struct sockaddr_storage* addr = sock->interface_addr.ss_family ? &sock->interface_addr : &sock->local_addr;
if (addr->ss_family == AF_INET) sp = ntohs(((const struct sockaddr_in*)addr)->sin_port);
else if (addr->ss_family == AF_INET6) sp = ntohs(((const struct sockaddr_in6*)addr)->sin6_port);
if (sp == (uint16_t)a.port) {
linkCount = sock->links_queue ? queue_entry_count(sock->links_queue) : 0;
break;
}
}
} else if (a.protocol == 2) {
linkCount = ownTcpActiveLinks;
}
if (linkCount > 0) prefix = QString("[%1] ").arg(linkCount);
}
lines.append(QString("%1<span style='color:%2;'>●</span> %3:%4:%5")
.arg(prefix, linkColor, proto, addrStr(a.addr.constData(), a.family)).arg(a.port));
}
/* Show ETCP links that are not in DB (non-self) */
if (conn) {
for (struct ETCP_LINK* lk = conn->links; lk; lk = lk->next) {
if (matchedLinks.contains(lk)) continue;
const struct sockaddr_storage* sa = &lk->remote_addr;
char ipbuf[INET6_ADDRSTRLEN]; QString lip; uint16_t lpo = 0;
if (sa->ss_family == AF_INET) {
struct sockaddr_in* sin = (struct sockaddr_in*)sa;
inet_ntop(AF_INET, &sin->sin_addr, ipbuf, sizeof(ipbuf));
lpo = ntohs(sin->sin_port); lip = QString::fromLocal8Bit(ipbuf);
} else if (sa->ss_family == AF_INET6) {
struct sockaddr_in6* sin6 = (struct sockaddr_in6*)sa;
inet_ntop(AF_INET6, &sin6->sin6_addr, ipbuf, sizeof(ipbuf));
lpo = ntohs(sin6->sin6_port); lip = QString::fromLocal8Bit(ipbuf);
} else { continue; }
QString proto = lk->is_tcp ? "TCP" : "UDP";
QString lc = (lk->link_state == 3 && lk->link_status == 1) ? "#4CAF50" : "#E53935";
lines.append(QString("<span style='color:%1;'>●</span> %2:%3:%4 [link]")
.arg(lc, proto, lip).arg(lpo));
}
} }
m_detailText->setHtml(lines.join("<br>")); m_detailText->setHtml(lines.join("<br>"));

Loading…
Cancel
Save