- chat_core.c: CREATE TABLE IF NOT EXISTS peers_* in ensure_channel_ready
- utun_node.cpp: GUI_ERROR redirected to debug log file via guiDebugFile()
- etcp_connections.c: reuse unindexed outbound conn (peer_node_id==0)
on cross-connect INIT to avoid 'Can not insert link to socket'
- etcp_connections: keepalive SEND/RECV/DECRYPT_OK: DEBUG→TRACE; DECRYPT_FAIL: WARN→DEBUG
- db_sync_on_conn_up: skip sync if !conn->initialized, wait for next UP event
- db_sync peer_check_timer+instance_add: also check conn->initialized
- chat_sync cs_on_conn_up: ignore conn_up before initialized (cs_send fails otherwise)
- db_sync_on_conn_up log now includes init= and links=
Protocol: added collision field to INIT_REQUEST_PKT (1 byte before ed25519_pubkey).
When two peers connect simultaneously, the one with is_server=0 (API-created
outbound link) is the master. Resolution by smaller node_id:
- We have master link + smaller node_id → send our INIT with collision=1
- We have master link + larger node_id → yield, process as slave
- Remote sends collision=1 → become slave unconditionally
- session_id change always forces reinit (genuine restart)
Removed unconditional etcp_conn_reinit on INIT_RESPONSE(0x03) — guarded by
reset_done flag. Server-side reinit now has collision check BEFORE reset_done
guard; session_id change penetrates reset_done protection.
Closes cross-connect reinit loop causing endless UP/DOWN flapping.
In etcp_conn_ready / etcp_on_up / etcp_on_down / etcp_connection_create /
tcp_server_on_link, callback chains were iterated with:
while (cbe) { cbe->fn(...); cbe = cbe->next; }
If the callback removes itself from the chain (e.g. ca_ready_cb calls
etcp_conn_remove_ready_cbk which u_free's the entry), cbe->next reads
freed memory → SIGSEGV.
Fixed by saving next pointer before invoking the callback:
while (cbe) { n = cbe->next; cbe->fn(...); cbe = n; }
Problem: when two peers connect simultaneously, each incoming
INIT_REQUEST(0x02) or INIT_RESPONSE(0x03) triggers etcp_conn_reinit
unconditionally, causing endless UP/DOWN flapping loop.
Fix: add reset_done flag to ETCP_CONN:
- 0 at creation and after explicit reinit (reinit allowed)
- set to 1 in etcp_conn_ready (connection stable, block reinit)
Three call sites guarded with !conn->reset_done:
- client: handle_init_response_client (INIT_RESPONSE 0x03)
- server: existing link INIT_REQUEST processing
- server: new link INIT_REQUEST processing
send_reset logic preserved unconditionally — only etcp_conn_reinit
itself is blocked when already stable.
- RECV: log every packet (src addr, link found, session_ready, decrypt result)
- RECV: log init decrypt rejection with packet code (catches 0x03 INIT_RESPONSE
silently dropped by init path)
- SEND: log destination addr+fd in send_init_response and etcp_encrypt_send
- REINIT: log full reason in server and client paths (code, session, got_init,
initialized, links_up state before reinit)
When two peers send INIT simultaneously, the first link occupies the socket.
Incoming INIT arriving after finds the existing outbound link by (ip,port)
instead of failing with 'Can not insert link to socket'.
new_conn is only true for the first INIT after server restart.
Subsequent INITs from same peer (recovery loop) see new_conn=0
and revert to old logic, sending 0x05 (no reset) and overwriting
the first 0x03 response.
got_initial_pkt stays 0 until client actually sends seq=1, so
server keeps sending 0x03 across all INIT retries until client
resets and starts from seq=1.
When server restarts, new ETCP_CONN has session_id=0 (calloc).
If client sends INIT_REQUEST_NOINIT (0x04) with session_id=0,
the condition conn->session_id != session_id is false (both 0),
so no reset was sent. Client kept old seq numbers while server
expected seq=1, causing 'Waiting for initial packet' deadlock.
Fix: add || new_conn to the condition — when server created a
fresh connection (was restarted), always send reset to client.
Server now checks both code==ETCP_INIT_REQUEST and session_id mismatch
to decide send_reset. Previously only session_id was checked, so if
session matched (both sides had 00000000), reinit was skipped even
when client explicitly requested reset (code 0x02).
Client side already correct: handle_init_response_client:1473 calls
etcp_conn_reinit if pkt_code==ETCP_INIT_RESPONSE (0x03).
- 1556: Normal decryption failed -> DEBUG_DEBUG (expected for INIT, no more spam)
- 1581: added 'INIT X25519 OK from %s' with source address
- 1604-1617: INFO log for decrypted packet type (PING/PONG/INIT) with peer_id+src
- 1662-1668: expanded INIT accepted log with all fields:
peer_id, mtu, link_id, socket_id, type, only_local, src_ip:src_port,
session_id, actual src (UDP) — shows NAT mismatch
- conn_mgr.c: 5 call sites used queue_entry_new(data_size) with data[] instead
of dgram — all etcp_route_send calls silently dropped. Fixed by switching to
dgram-based allocation (queue_entry_new(0)+u_malloc) matching all other callers.
- DIRCECT_REQ reuses already-allocated pkt as qe->dgram (no extra memcpy).
- etcp_router.c:1078 — 'empty entry' now shows dgram=%p len=%u dst=0x... force=%d
- etcp_connections.c:1139 — 'bad args' now shows all arg pointers to identify NULL
- etcp_connections.c:1145 — 'no socket' now shows addr_family=%d
- conn_mgr.c:633 — 'no candidates' now notes direct+reverse failed
- Renamed TOPO_BGP to TOPO_GROUP with topo_group_id (64bit)
- Added TOPO_GROUPS container (ll_queue group_list) in UTUN_INSTANCE
- Memory pools moved from TOPO_GROUP to TOPO_GROUPS (instance-level)
- Default group: TOPO_GROUP_UTUN = 0x8000000000000000
- topo_groups_get_default() searches by group_id, not just first entry
- All topo_bgp_* renamed to topo_group_*; function signatures updated
- Files: topo_bgp.h/c -> topo_group.h/c
- NODEINFO_MSG (protocol, packed): added flags byte + group_id field
- NODEINFO (memory): ref_count, linked list heads instead of inline arrays
- NODEINFO_ROUTES: separate struct with linked list subnet heads
- NODEINFO_Q: node*, routes*, tranzit_data*, hop_list* as separate mallocs
- 6 memory_pools in ROUTE_BGP for NI_* linked list items
- ni_list_count() universal counter via _ni_head cast
- nodeinfo_serialize/deserialize for protocol <-> memory conversion
- NODEINFO_FLAG_SEND_SUBNETS controls subnet data in protocol
- group_id defaults: utun=NODEINFO_GROUP_UTUN(1) with subnets
Fixes:
- deserialization: data+2 instead of data+sizeof(BGP_NODEINFO_PACKET)
- memset: start after ll_entry to preserve ll.size
- hop_src: subtract hop_count*8 to point at correct dynamic offset
- same-ver branch: remove_path(conn) instead of remove_path_by_hop(peer)
- double-free in route_bgp_remove_conn/process_withdraw
- conn_mgr_add_alien_node: rewritten for new structures
- all test files updated for new API
- etcp_connections: fix link leak & UAF in etcp_socket_remove — remove_link inside etcp_link_close shifts array, skip NULL set and i++
- stcp_server: fix UAF in stcp_conn_process_recv — defer free via uasync_call_soon after stcp_conn_do_close
- etcp: save pkt_len before queue_data_put to output_queue (callback may free entry synchronously)
- socks_proxy: add pool bounds check before memcpy, UINT16_MAX truncation guard, freed flag
- tcp_proxy_server: reorder cleanup (cancel waiters before tcp_conn_destroy), UINT16_MAX guard
- test_route6_lib: increase nodes[] array to STRESS_NODES + STRESS_OPS
- keepalive_adaptive=0 disables adaptive keepalive period growth,
keeping it fixed at 200ms for faster timeout detection in tests
- test_bgp_triangle: 5-node triangle topology test (6 phases):
validates alternative path recording (fix#1), cascading node
removal on full isolation, and full recovery
- config generation via utun_instance_create_from_str() with
pre-generated keys — no temp files needed
Both req (INIT_REQUEST) and resp (INIT_RESPONSE) point to pkt->data.
resp->peer_port at offset 23-24 overwrites req->src_ipv4[0..1] at same offset.
Save src_ipv4/src_port before building the response.
- Extract ETCP_INIT_REQUEST_PKT / ETCP_INIT_RESPONSE_PKT named structs
- Replace anonymous structs and manual offset parsing with typed struct access
- Add src_ipv4/src_port fields (V2) to INIT REQUEST for DIRECT detection
- Server compares reported client addr with observed src; match + public IP → NAT_TYPE_DIRECT
- Skip STUN NAT check for DIRECT links
- route_bgp: handle NAT_TYPE_DIRECT → NAT_VERIFIED_DIRECT in handle_nat_info
last_recv_local_time was not set in the server INIT processing path,
causing the keepalive timer to see a stale timestamp and trigger a
false link-down → route_bgp_remove_conn() right after reconnect.
Routes could be deleted before the first normal packet from the
client updated the timestamp via process_decrypted.
- Add acked_bytes/acked_packets to struct ETCP_LINK (init, reset, increment per ACK)
- Add DEBUG_CATEGORY_BBR (23) for BBR-specific debug output
- Add BBR input/output DEBUG_DEBUG around bbr_main call in etcp_ack_recv
- Add "bbr" category name to debug_config and etcpmon GUI
- etcp_link_update_inflight_lim: self-contained method with clamping,
send_blocked_inflight check, loadbalancer_link_ready on cwnd increase
- etcp_conn_on_inflight_lim_changed: recalc optimal_inflight + resume input
- etcp_ack_recv: use etcp_link_update_inflight_lim instead of manual set
- etcp_request_pkt: fix line 928 check old link (inf_pkt->last_link) not new
- etcp_link_close: recalc optimal_inflight on link removal (both branches)
- etcp_socket_remove: fix dangling pointer loop (nullify after close)
- uasync_print_resources: show timer names, remain time, deleted entries
- diagnostics in utun_instance_destroy and test_etcp_reconnect
memory_pool: memory_pool_is_freed(pool,obj) — поиск obj в free-списке
tw_pcbs (3 места): !ctx→halt и is_freed→halt в начале итерации
— ловит висячий PCB до re-alloc и после re-alloc
etcp: is_freed→halt перед etcp_conn_input (caller + callee)
— ловит pkt освобождённый до входа
tcp_alloc: убран старый скан tw_pcbs (заменён на is_freed)
все dangling проверки — halt (while(1)) вместо break/return
Shows mtu, s_rand, s_max, offset/xoffset, and whether capped.
RESP: removed old hardcoded 1472+26 cap, replaced by formula.
Both paths use consistent formula based on #defines.
Hardcoded 1472-46 cap exceeded link MTU=1460, causing 'packet too long'
error on INIT handshake. Use link->mtu - UDP_HDR_SIZE - offset - 19
instead of fixed 1472.