@ -80,6 +80,13 @@ static void etcp_link_send_init(struct ETCP_LINK* link, uint8_t reset) {
dgram - > data [ offset + + ] = ( node_id > > 16 ) & 0xFF ;
dgram - > data [ offset + + ] = ( node_id > > 8 ) & 0xFF ;
dgram - > data [ offset + + ] = node_id & 0xFF ;
// session_id (4 bytes) - для защиты от ложного reinit
uint32_t session_id = link - > etcp - > session_id ;
dgram - > data [ offset + + ] = ( session_id > > 24 ) & 0xFF ;
dgram - > data [ offset + + ] = ( session_id > > 16 ) & 0xFF ;
dgram - > data [ offset + + ] = ( session_id > > 8 ) & 0xFF ;
dgram - > data [ offset + + ] = session_id & 0xFF ;
dgram - > data [ offset + + ] = ( link - > mtu_local > > 8 ) & 0xFF ;
dgram - > data [ offset + + ] = link - > mtu_local & 0xFF ;
@ -1200,6 +1207,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
struct {
uint8_t code ;
uint8_t id [ 8 ] ;
uint8_t session_id [ 4 ] ;
uint8_t mtu [ 2 ] ;
uint8_t keepalive [ 2 ] ;
uint8_t recovery [ 2 ] ;
@ -1283,6 +1291,9 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
goto ec_fr ;
} // не init
uint32_t session_id = be32toh ( * ( uint32_t * ) ack_hdr - > session_id ) ;
DEBUG_DEBUG ( DEBUG_CATEGORY_CONNECTION , " INIT request session_id=%08x " , session_id ) ;
struct ETCP_CONN * conn = e_sock - > instance - > connections ;
while ( conn ) { // ищем есть ли подключение к этому пиру
if ( conn - > peer_node_id = = peer_id ) break ;
@ -1296,6 +1307,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
if ( ! conn ) { errorcode = 55 ; DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTION , " failed to create connection " ) ; goto ec_fr ; }
memcpy ( & conn - > crypto_ctx , & sc , sizeof ( sc ) ) ;
conn - > peer_node_id = peer_id ;
conn - > session_id = session_id ;
etcp_update_log_name ( conn ) ;
DEBUG_INFO ( DEBUG_CATEGORY_GENERAL , " New connection received on socket %s: log_name=%s peer_id=%lu peer:%s " , e_sock - > name , conn - > log_name , ( unsigned long ) peer_id , sockaddr_storage_to_str ( & addr ) . str ) ;
DEBUG_DEBUG ( DEBUG_CATEGORY_CONNECTION , " New connection from %s peer_id=%ld etcp=%p " , ip_to_str ( & addr , addr . ss_family ) . str , peer_id , conn ) ;
@ -1336,11 +1348,14 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
// For CHANNEL_INIT (0x04): if link already initialized - no reset, otherwise reset
// For INIT_REQUEST (0x02): always reset
if ( ack_hdr - > code = = ETCP_INIT_REQUEST_NOINIT & & conn - > initialized ) {
send_reset = 0 ; // Link is up, respond without reset
// Check session_id: if same - no reinit, if different - client restarted, do reinit
if ( conn - > session_id = = session_id ) {
send_reset = 0 ; // Same session, no reinit needed
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " same session_id, skip reinit " ) ;
} else {
send_reset = 1 ; // INIT_REQUEST (0x02) or uninitialized link - send reset
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " do reinit " ) ;
send_reset = 1 ; // New session or uninitialized link - send reset
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " new session_id %08x (was %08x), do reinit " , session_id , conn - > session_id ) ;
conn - > session_id = session_id ;
etcp_conn_reinit ( conn ) ;
}
@ -1358,10 +1373,11 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
link - > remote_socket_id = ack_hdr - > remote_socket_id ;
link - > remote_only_local = ack_hdr - > only_local ;
// For new links: INIT_REQUEST (0x02) causes reset, CHANNEL_INIT (0x04) does not
if ( ack_hdr - > code = = ETCP_INIT_REQUEST | | new_conn ) {
send_reset = 1 ; // INIT_REQUEST (0x02) or uninitialized link - send reset
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " do reinit 2 " ) ;
// For new links: check session_id to avoid false reinit
if ( conn - > session_id ! = session_id ) {
send_reset = 1 ; // New session or uninitialized link - send reset
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " new session_id %08x (was %08x) for new link, do reinit " , session_id , conn - > session_id ) ;
conn - > session_id = session_id ;
etcp_conn_reinit ( conn ) ;
}
link - > keepalive_interval = ( ack_hdr - > keepalive [ 0 ] < < 8 ) | ack_hdr - > keepalive [ 1 ] ;
@ -1376,6 +1392,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
struct {
uint8_t code ;
uint8_t id [ 8 ] ;
uint8_t session_id [ 4 ] ;
uint8_t mtu [ 2 ] ;
uint8_t link_id ;
uint8_t remote_socket_id ;
@ -1385,7 +1402,8 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
} * ack_repl_hdr = ( void * ) & pkt - > data [ 0 ] ;
// Set response code: 0x03 (with reset) or 0x05 (without reset)
if ( send_reset ! = 0 | | new_conn ! = 0 | | ack_hdr - > code = = ETCP_INIT_REQUEST ) {
// response with init (0x03) only if reinit was actually done on server side
if ( send_reset ! = 0 ) {
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " send init_response with reset " ) ;
ack_repl_hdr - > code = ETCP_INIT_RESPONSE ; // 0x03 - with reset
} else {
@ -1393,6 +1411,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
ack_repl_hdr - > code = ETCP_INIT_RESPONSE_NOINIT ; // 0x05 - without reset
}
* ( uint64_t * ) ack_repl_hdr - > id = htobe64 ( e_sock - > instance - > node_id ) ;
* ( uint32_t * ) ack_repl_hdr - > session_id = htobe32 ( conn - > session_id ) ;
ack_repl_hdr - > mtu [ 0 ] = link - > mtu_local > > 8 ;
ack_repl_hdr - > mtu [ 1 ] = link - > mtu_local ;
@ -1490,6 +1509,16 @@ process_decrypted:
for ( int i = 0 ; i < 8 ; i + + ) {
server_node_id = ( server_node_id < < 8 ) | pkt - > data [ offset + + ] ;
}
uint32_t resp_session_id = ( pkt - > data [ offset ] < < 24 ) | ( pkt - > data [ offset + 1 ] < < 16 ) | ( pkt - > data [ offset + 2 ] < < 8 ) | pkt - > data [ offset + 3 ] ;
offset + = 4 ;
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " INIT_RESPONSE session_id=%08x " , resp_session_id ) ;
// Check session_id: ignore response if it doesn't match our session
if ( resp_session_id ! = link - > etcp - > session_id ) {
DEBUG_WARN ( DEBUG_CATEGORY_CONNECTION , " [%s] INIT_RESPONSE session_id mismatch: got %08x, expected %08x, ignoring " ,
link - > etcp - > log_name , resp_session_id , link - > etcp - > session_id ) ;
memory_pool_free ( e_sock - > instance - > pkt_pool , pkt ) ;
return ;
}
link - > mtu_remote = ( pkt - > data [ offset + + ] < < 8 ) | pkt - > data [ offset + + ] ;
link - > mtu = link - > mtu_local < link - > mtu_remote ? link - > mtu_local : link - > mtu_remote ;
link - > remote_link_id = pkt - > data [ offset + + ] ;
@ -1497,7 +1526,7 @@ process_decrypted:
link - > remote_only_local = pkt - > data [ offset + + ] ;
// Parse NAT IP:port from response (new format includes 4+2 bytes)
if ( pkt_len > = 19 ) {
if ( pkt_len > = 23 ) {
uint32_t new_nat_ip ;
memcpy ( & new_nat_ip , & pkt - > data [ offset ] , 4 ) ;
offset + = 4 ;
@ -1681,13 +1710,22 @@ int init_connections(struct UTUN_INSTANCE* instance) {
// Create ETCP connection for this client
struct ETCP_CONN * etcp_conn = etcp_connection_create ( instance , client - > name ) ;
if ( ! etcp_conn ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CONNECTION , " Failed to create ETCP connection for client %s " , client - > name ) ;
client = client - > next ;
continue ;
}
// Generate session_id for this client connection
if ( random_bytes ( ( uint8_t * ) & etcp_conn - > session_id , sizeof ( etcp_conn - > session_id ) ) ! = 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CRYPTO , " Failed to generate session_id for client %s " , client - > name ) ;
etcp_connection_close ( etcp_conn ) ;
client = client - > next ;
continue ;
}
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " Client %s session_id=%08x " , client - > name , etcp_conn - > session_id ) ;
// Initialize crypto context for this connection
if ( sc_init_ctx ( & etcp_conn - > crypto_ctx , & instance - > my_keys ) ! = SC_OK ) {
DEBUG_ERROR ( DEBUG_CATEGORY_CRYPTO , " init_connections: failed to initialize crypto context for client %s " , client - > name ) ;