@ -86,7 +86,8 @@ void tcp_server_on_link(struct stcp_link *link, struct ETCP_SOCKET *tcp_sock) {
DEBUG_INFO ( DEBUG_CATEGORY_ETCP , " tcp_server_on_link: new ETCP_CONN peer=0x%016llx " , ( unsigned long long ) node_id ) ;
}
const struct sockaddr_storage * ra = stcp_link_get_remote_addr ( link ) ;
const struct sockaddr_storage * ra = stcp_link_get_peer_addr ( link ) ;
if ( ! ra ) ra = stcp_link_get_remote_addr ( link ) ;
struct ETCP_LINK * tlink = etcp_link_new ( conn , tcp_sock , ra , 1 ) ;
if ( ! tlink ) { DEBUG_ERROR ( DEBUG_CATEGORY_ETCP , " tcp_server_on_link: etcp_link_new failed " ) ; return ; }
tlink - > tcp_link = link ;
@ -176,7 +177,7 @@ static void etcp_link_send_init(struct ETCP_LINK* link, uint8_t reset, uint8_t c
* ( uint64_t * ) req - > node_id = htobe64 ( link - > etcp - > instance - > node_id ) ;
* ( uint32_t * ) req - > session_id = htobe32 ( link - > etcp - > session_id ) ;
* ( uint16_t * ) req - > mtu = htobe16 ( link - > mtu_local ) ;
* ( uint16_t * ) req - > keepalive = htobe16 ( link - > keepalive_interval ) ;
* ( uint16_t * ) req - > keepalive = htobe16 ( link - > etcp - > instance - > keepalive_interval ) ;
* ( uint16_t * ) req - > recovery = htobe16 ( link - > recovery_interval / 100 ) ;
req - > link_id = link - > local_link_id ;
req - > socket_id = link - > conn ? link - > conn - > sock_id : 0 ;
@ -196,6 +197,7 @@ static void etcp_link_send_init(struct ETCP_LINK* link, uint8_t reset, uint8_t c
}
req - > collision = collision ;
memcpy ( req - > ed25519_pubkey , link - > etcp - > instance - > my_ed25519_pubkey , SC_PUBKEY_SIZE ) ;
req - > device_type = link - > etcp - > instance - > client_type ;
size_t offset = ETCP_INIT_REQ_SIZE ;
// padding
@ -269,7 +271,7 @@ static void etcp_link_init_timer_cbk(void* arg) {
}
link - > init_timer = uasync_set_timeout ( link - > etcp - > instance - > ua , link - > init_timeout , link , etcp_link_init_timer_cbk , " link_init " ) ;
if ( link - > link_state = = 3 & & link - > initialized ) { DEBUG_DEBUG ( DEBUG_CATEGORY_KEEPALIVE , " [%s] init_timer: SUPPRESSED state=%d init=%d link_status=%d recv_ka=%d remote_ka=%d links_up=%d " , link - > etcp - > log_name , link - > link_state , link - > initialized , link - > link_status , link - > recv_keepalive , link - > remote_keepalive , link - > etcp - > links_up ) ; return ; }
if ( link - > link_state = = LINK_STATE_CONNECTED & & link - > initialized ) { DEBUG_DEBUG ( DEBUG_CATEGORY_KEEPALIVE , " [%s] init_timer: SUPPRESSED state=%d init=%d link_status=%d recv_ka=%d remote_ka=%d links_up=%d " , link - > etcp - > log_name , link - > link_state , link - > initialized , link - > link_status , link - > recv_keepalive , link - > remote_keepalive , link - > etcp - > links_up ) ; return ; }
if ( link - > etcp - > links_up > 0 ) { DEBUG_DEBUG ( DEBUG_CATEGORY_KEEPALIVE , " [%s] init_timer: SUPPRESSED (links_up=%d > 0) " , link - > etcp - > log_name , link - > etcp - > links_up ) ; return ; }
if ( link - > etcp - > fin_wait ) { DEBUG_DEBUG ( DEBUG_CATEGORY_KEEPALIVE , " [%s] init_timer: SUPPRESSED (fin_wait) " , link - > etcp - > log_name ) ; return ; }
if ( link - > is_tcp ) { etcp_tcp_link_start_reconnect ( link ) ; return ; } // TCP uses STCP handshake, not ETCP INIT
@ -288,7 +290,7 @@ void etcp_link_enter_init(struct ETCP_LINK* link) {//
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " " ) ;
if ( ! link ) return ;
int old_state = link - > link_state ;
link - > link_state = 1 ; // handshake
link - > link_state = LINK_STATE_HANDSHAKE ; // handshake
etcp_fire_link_status_cbk ( link , old_state , link - > link_status ) ;
if ( link - > is_server ! = 0 ) return ;
etcp_link_send_init ( link , 1 , 0 ) ; // init with reset
@ -299,7 +301,7 @@ void etcp_link_enter_reinit(struct ETCP_LINK* link) {
DEBUG_TRACE ( DEBUG_CATEGORY_CONNECTION , " " ) ;
if ( ! link ) return ;
int old_state = link - > link_state ;
link - > link_state = 2 ; // reconnect
link - > link_state = LINK_STATE_TRY_RECONNECT ; // reconnect
etcp_fire_link_status_cbk ( link , old_state , link - > link_status ) ;
etcp_on_link_down ( link - > etcp , link ) ;
if ( link - > is_server ! = 0 ) return ;
@ -315,6 +317,19 @@ void etcp_link_enter_reinit(struct ETCP_LINK* link) {
}
// Вычислить keepalive по типу устройств: оба десктоп/сервер → min, иначе (есть mobile) → max
static uint16_t negotiate_keepalive ( uint8_t my_type , uint16_t my_ka ,
uint8_t peer_type , uint16_t peer_ka ) {
int my_lp = ( my_type = = CLIENT_TYPE_MOBILE ) ;
int peer_lp = ( peer_type = = CLIENT_TYPE_MOBILE ) ;
uint16_t result = ( my_lp | | peer_lp ) ? ( my_ka > peer_ka ? my_ka : peer_ka )
: ( my_ka < peer_ka ? my_ka : peer_ka ) ;
DEBUG_INFO ( DEBUG_CATEGORY_KEEPALIVE , " negotiate: my=%d(type=%d) peer=%d(type=%d) → %d (rule=%s) " ,
my_ka , my_type , peer_ka , peer_type , result ,
( my_lp | | peer_lp ) ? " max(low_power) " : " min(both_desktop) " ) ;
return result ;
}
// Send empty keepalive packet (only timestamp, no sections)
static void etcp_link_send_keepalive ( struct ETCP_LINK * link ) {
DEBUG_TRACE ( DEBUG_CATEGORY_KEEPALIVE , " " ) ;
@ -403,6 +418,8 @@ static void keepalive_timer_cb(void* arg) {
uint64_t now = get_time_tb ( ) ;
uint64_t timeout_units = ( uint64_t ) link - > keepalive_timeout * 10 ; // ms -> 0.1ms units
uint64_t elapsed = now - link - > last_recv_local_time ;
DEBUG_DEBUG ( DEBUG_CATEGORY_DEBUG , " [%s] ka_check: recv=%d elapsed=%llu timeout=%llu " ,
link - > etcp - > log_name , link - > recv_keepalive , ( unsigned long long ) elapsed , ( unsigned long long ) timeout_units ) ;
if ( elapsed > timeout_units ) {
if ( link - > recv_keepalive ! = 0 ) {
@ -835,13 +852,15 @@ void etcp_socket_remove(struct ETCP_SOCKET* conn) {
}
struct ll_entry * entry ;
while ( ( entry = conn - > links_queue - > head ) ! = NULL ) {
struct link_queue_entry * lqe = ( struct link_queue_entry * ) entry - > data ;
etcp_link_close ( lqe - > link ) ;
if ( conn - > links_queue ) {
struct ll_entry * entry ;
while ( ( entry = conn - > links_queue - > head ) ! = NULL ) {
struct link_queue_entry * lqe = ( struct link_queue_entry * ) entry - > data ;
etcp_link_close ( lqe - > link ) ;
}
queue_free ( conn - > links_queue ) ;
conn - > links_queue = NULL ;
}
queue_free ( conn - > links_queue ) ;
conn - > links_queue = NULL ;
u_free ( conn ) ;
}
@ -925,8 +944,8 @@ struct ETCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SE
}
}
ts - > next = instance - > tcp_sockets ;
instance - > tcp_sockets = ts ;
ts - > next = instance - > e tcp_sockets;
instance - > e tcp_sockets = ts ;
{ char loc_str [ 64 ] = " none " , if_str [ 64 ] = " none " ;
if ( ts - > local_addr . ss_family ) snprintf ( loc_str , sizeof ( loc_str ) , " %s " , sockaddr_storage_to_str ( & ts - > local_addr ) . str ) ;
if ( ts - > interface_addr . ss_family ) snprintf ( if_str , sizeof ( if_str ) , " %s " , sockaddr_storage_to_str ( & ts - > interface_addr ) . str ) ;
@ -938,7 +957,7 @@ struct ETCP_SOCKET* tcp_socket_add(struct UTUN_INSTANCE* instance, struct CFG_SE
void tcp_socket_remove ( struct ETCP_SOCKET * sock ) {
if ( ! sock | | ! sock - > instance ) return ;
struct UTUN_INSTANCE * inst = sock - > instance ;
struct ETCP_SOCKET * * pp = & inst - > tcp_sockets ;
struct ETCP_SOCKET * * pp = & inst - > e tcp_sockets;
while ( * pp & & * pp ! = sock ) pp = & ( * pp ) - > next ;
if ( * pp ) * pp = sock - > next ;
DEBUG_INFO ( DEBUG_CATEGORY_SOCKET , " tcp_socket_remove: %s sock_id=%u " , sock - > name , sock - > sock_id ) ;
@ -1116,6 +1135,7 @@ void etcp_link_close(struct ETCP_LINK* link) {
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " [%s] Link %d closed: addr=%s rcvd=%zub ack=%llub infl=%ub/%upkt " ,
link - > etcp - > log_name , link - > local_link_id , sockaddr_storage_to_str ( & link - > remote_addr ) . str , link - > total_decrypted ,
( unsigned long long ) link - > acked_bytes , link - > inflight_bytes , link - > inflight_packets ) ;
etcp_fire_link_status_cbk ( link , link - > link_state , link - > link_status ) ;
u_free ( link - > bbr ) ;
u_free ( link ) ;
}
@ -1141,10 +1161,17 @@ void etcp_link_enter_ready_tcp(struct ETCP_LINK *link) {
etcp_conn_reinit ( etcp , " tcp session changed " ) ;
}
etcp - > session_id = peer_sid ;
link - > peer_device_type = stcp_link_get_peer_device_type ( link - > tcp_link ) ;
{ uint16_t peer_ka = stcp_link_get_peer_keepalive_interval ( link - > tcp_link ) ;
link - > keepalive_interval = negotiate_keepalive ( etcp - > instance - > client_type ,
etcp - > instance - > keepalive_interval , link - > peer_device_type , peer_ka ) ; }
}
link - > initialized = 1 ; link - > link_state = 3 ; link - > link_status = 1 ;
int old_state = link - > link_state ;
link - > initialized = 1 ; link - > link_state = LINK_STATE_CONNECTED ; link - > link_status = 1 ;
link - > recv_keepalive = 1 ;
link - > last_recv_local_time = get_time_tb ( ) ;
if ( ! link - > mtu_remote ) link - > mtu_remote = link - > mtu ;
etcp - > got_initial_pkt = 1 ;
etcp - > reset_done = 1 ;
@ -1154,6 +1181,7 @@ void etcp_link_enter_ready_tcp(struct ETCP_LINK *link) {
etcp_link_send_keepalive ( link ) ;
start_keepalive_timer ( link ) ;
loadbalancer_link_ready ( link ) ;
etcp_fire_link_status_cbk ( link , old_state , link - > link_status ) ;
DEBUG_INFO ( DEBUG_CATEGORY_ETCP , " [%s] TCP link %d UP (mtu=%d init=%d up=%d tcp_links=%d) " ,
etcp - > log_name , link - > local_link_id , link - > mtu ,
etcp - > initialized , etcp - > links_up , etcp - > tcp_link_count ) ;
@ -1168,8 +1196,15 @@ static void tcp_link_reconnect_cb(void *arg) {
if ( link - > tcp_reconnect_delay_ms = = 0 ) link - > tcp_reconnect_delay_ms = 1000 ;
DEBUG_INFO ( DEBUG_CATEGORY_ETCP , " [%s] TCP link %d reconnect attempt (delay=%ums) " , link - > etcp - > log_name , link - > local_link_id , link - > tcp_reconnect_delay_ms ) ;
uint16_t port = ntohs ( ( ( struct sockaddr_in * ) & link - > remote_addr ) - > sin_port ) ;
struct sockaddr_storage bind_addr ; const struct sockaddr_storage * laddr = NULL ;
if ( link - > conn & & link - > conn - > interface_addr . ss_family ) {
memcpy ( & bind_addr , & link - > conn - > interface_addr , sizeof ( bind_addr ) ) ;
if ( bind_addr . ss_family = = AF_INET6 ) ( ( struct sockaddr_in6 * ) & bind_addr ) - > sin6_port = 0 ;
else ( ( struct sockaddr_in * ) & bind_addr ) - > sin_port = 0 ;
laddr = & bind_addr ;
}
struct stcp_link_config tcp_cfg = { . ua = link - > etcp - > instance - > ua , . my_keys = & link - > etcp - > instance - > my_keys , . inst = link - > etcp - > instance , . peer_pubkey = link - > etcp - > crypto_ctx . peer_public_key ,
. peer_pubkey_mode = 0 , . remote_addr = & link - > remote_addr , . remote_port = port , . got_initial_pkt = link - > etcp - > got_initial_pkt , . session_id = link - > etcp - > session_id } ;
. peer_pubkey_mode = 0 , . remote_addr = & link - > remote_addr , . remote_port = port , . local_addr = laddr , . got_initial_pkt = link - > etcp - > got_initial_pkt , . session_id = link - > etcp - > session_id } ;
struct stcp_link * sl = stcp_link_connect ( & tcp_cfg ) ;
if ( ! sl ) { link - > tcp_reconnect_delay_ms * = 2 ; if ( link - > tcp_reconnect_delay_ms > 30000 ) link - > tcp_reconnect_delay_ms = 30000 ;
link - > tcp_reconnect_timer = uasync_set_timeout ( link - > etcp - > instance - > ua , ( int ) ( link - > tcp_reconnect_delay_ms * 10 ) , link , tcp_link_reconnect_cb , " tcp_rct " ) ; return ; }
@ -1179,13 +1214,23 @@ static void tcp_link_reconnect_cb(void *arg) {
void etcp_tcp_link_start_connect ( struct ETCP_LINK * link , struct sockaddr_storage * addr , uint16_t port ) {
if ( ! link | | ! link - > etcp | | ! addr ) return ;
if ( ! link - > conn ) { for ( struct ETCP_SOCKET * s = link - > etcp - > instance - > etcp_sockets ; s ; s = s - > next ) { if ( s - > is_tcp ) { link - > conn = s ; break ; } }
if ( ! link - > conn ) { DEBUG_ERROR ( DEBUG_CATEGORY_ETCP , " [%s] no TCP socket in instance, cannot start TCP link %d " , link - > etcp - > log_name , link - > local_link_id ) ; return ; } }
memcpy ( & link - > remote_addr , addr , sizeof ( * addr ) ) ;
struct sockaddr_storage bind_addr ; const struct sockaddr_storage * laddr = NULL ;
if ( link - > conn - > interface_addr . ss_family ) {
memcpy ( & bind_addr , & link - > conn - > interface_addr , sizeof ( bind_addr ) ) ;
if ( bind_addr . ss_family = = AF_INET6 ) ( ( struct sockaddr_in6 * ) & bind_addr ) - > sin6_port = 0 ;
else ( ( struct sockaddr_in * ) & bind_addr ) - > sin_port = 0 ;
laddr = & bind_addr ;
}
struct stcp_link_config tcp_cfg = {
. ua = link - > etcp - > instance - > ua ,
. my_keys = & link - > etcp - > instance - > my_keys ,
. inst = link - > etcp - > instance ,
. peer_pubkey = link - > etcp - > crypto_ctx . peer_public_key ,
. peer_pubkey_mode = 0 , . remote_addr = & link - > remote_addr , . remote_port = port ,
. local_addr = laddr ,
. got_initial_pkt = link - > etcp - > got_initial_pkt ,
. session_id = link - > etcp - > session_id } ;
struct stcp_link * sl = stcp_link_connect ( & tcp_cfg ) ;
@ -1201,7 +1246,7 @@ void etcp_tcp_link_start_reconnect(struct ETCP_LINK *link) {
if ( link - > etcp - > state = = 2 ) return ;
if ( link - > tcp_reconnect_timer ) return ;
if ( link - > tcp_link ) { stcp_link_close ( link - > tcp_link ) ; link - > tcp_link = NULL ; }
link - > link_state = 1 ;
link - > link_state = LINK_STATE_HANDSHAKE ;
if ( link - > etcp - > tcp_link_count > 0 ) link - > etcp - > tcp_link_count - - ;
link - > tcp_reconnect_timer = uasync_set_timeout ( link - > etcp - > instance - > ua , ( int ) ( link - > tcp_reconnect_delay_ms * 10 ) , link , tcp_link_reconnect_cb , " tcp_rct " ) ;
}
@ -1210,9 +1255,12 @@ static void tcp_link_close_cb(struct stcp_link *sl, int err, void *arg) {
struct ETCP_LINK * link = ( struct ETCP_LINK * ) arg ;
if ( ! link | | ! link - > etcp ) return ;
if ( link - > etcp - > state = = 2 ) return ;
int old_state = link - > link_state ;
stcp_link_close ( sl ) ;
link - > tcp_link = NULL ;
etcp_fire_link_status_cbk ( link , old_state , 0 ) ;
if ( link - > is_server ) {
DEBUG_INFO ( DEBUG_CATEGORY_ETCP , " [%s] TCP server link %d down err=%d, closing " , link - > etcp - > log_name , link - > local_link_id , err ) ;
etcp_on_link_down ( link - > etcp , link ) ;
@ -1229,13 +1277,21 @@ static int etcp_tcp_send(struct ETCP_DGRAM* dgram) {
if ( ! link - > tcp_link | | ! stcp_link_is_ready ( link - > tcp_link ) ) return - 1 ;
link - > pkt_sent_since_keepalive = 1 ;
dgram - > flag_up = 1 ;
dgram - > timestamp = get_current_timestamp ( ) ;
size_t total_len = 3 + dgram - > data_len ;
uint8_t * buf = u_malloc ( total_len ) ;
if ( ! buf ) { DEBUG_ERROR ( DEBUG_CATEGORY_ETCP , " [%s] TCP send: malloc %zu failed " , link - > etcp - > log_name , total_len ) ; return - 1 ; }
memcpy ( buf , & dgram - > timestamp , 2 ) ;
buf [ 2 ] = dgram - > flag_up ;
if ( dgram - > data_len ) memcpy ( buf + 3 , dgram - > data , dgram - > data_len ) ;
int rc ;
if ( link - > send_hook ) rc = ( int ) link - > send_hook ( 0 , dgram - > data , dgram - > data_len , NULL , 0 , link , link - > send_hook_ctx ) ;
else if ( link - > tcp_link ) rc = stcp_link_send ( link - > tcp_link , dgram - > data , dgram - > data_len ) = = 0 ? ( int ) dgram - > data_len : - 1 ;
if ( link - > send_hook ) rc = ( int ) link - > send_hook ( 0 , buf , total _len, NULL , 0 , link , link - > send_hook_ctx ) ;
else if ( link - > tcp_link ) rc = stcp_link_send ( link - > tcp_link , buf , total _len) = = 0 ? ( int ) dgram - > data_len : - 1 ;
else rc = - 1 ;
u_free ( buf ) ;
if ( rc > 0 ) link - > total_encrypted + = ( size_t ) rc ;
DEBUG_DEBUG ( DEBUG_CATEGORY_ETCP , " [%s] TCP send: link=%d dlen=%d rc=%d via=%s " ,
link - > etcp - > log_name , link - > local_link_id , dgram - > data_len , rc ,
DEBUG_DEBUG ( DEBUG_CATEGORY_ETCP , " [%s] TCP send: link=%d total=%zu dlen=%d rc=%d via=%s " ,
link - > etcp - > log_name , link - > local_link_id , total_len , dgram - > data_len , rc ,
link - > send_hook ? " hook " : ( link - > tcp_link ? " stcp " : " NONE " ) ) ;
return rc ;
}
@ -1686,6 +1742,8 @@ static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pk
}
}
memcpy ( resp - > ed25519_pubkey , e_sock - > instance - > my_ed25519_pubkey , SC_PUBKEY_SIZE ) ;
resp - > device_type = e_sock - > instance - > client_type ;
* ( uint16_t * ) resp - > keepalive = htobe16 ( e_sock - > instance - > keepalive_interval ) ;
pkt - > noencrypt_len = 0 ;
pkt - > link = link ;
link - > recv_keepalive = 1 ;
@ -1718,7 +1776,7 @@ static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pk
memory_pool_free ( e_sock - > instance - > pkt_pool , pkt ) ;
link - > initialized = 1 ;
{ int old_state = link - > link_state ; link - > link_state = 3 ; etcp_fire_link_status_cbk ( link , old_state , link - > link_status ) ; }
{ int old_state = link - > link_state ; link - > link_state = LINK_STATE_CONNECTED ; etcp_fire_link_status_cbk ( link , old_state , link - > link_status ) ; }
if ( link - > init_timer ) {
uasync_cancel_timeout ( link - > etcp - > instance - > ua , link - > init_timer ) ;
link - > init_timer = NULL ;
@ -1735,6 +1793,7 @@ static void send_init_response(struct ETCP_SOCKET* e_sock, struct ETCP_DGRAM* pk
}
static int handle_init_response_client ( struct ETCP_SOCKET * e_sock , struct ETCP_DGRAM * pkt , struct ETCP_LINK * link , uint8_t pkt_code , size_t pkt_len ) {
if ( ! e_sock ) return - 1 ;
if ( pkt_len < ETCP_INIT_RESP_SIZE ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ETCP , " INIT_RESPONSE too short: pkt_len=%zu " , pkt_len ) ;
return 46 ;
@ -1817,12 +1876,16 @@ static int handle_init_response_client(struct ETCP_SOCKET* e_sock, struct ETCP_D
memcpy ( link - > etcp - > peer_ed25519_pubkey , resp - > ed25519_pubkey , SC_PUBKEY_SIZE ) ;
DEBUG_DEBUG ( DEBUG_CATEGORY_CRYPTO , " [%s] Received Ed25519 pubkey from peer " , link - > etcp - > log_name ) ;
link - > peer_device_type = resp - > device_type ;
{ uint16_t server_ka = ( resp - > keepalive [ 0 ] < < 8 ) | resp - > keepalive [ 1 ] ;
link - > keepalive_interval = negotiate_keepalive ( link - > etcp - > instance - > client_type ,
link - > etcp - > instance - > keepalive_interval , resp - > device_type , server_ka ) ; }
link - > etcp - > peer_node_id = server_node_id ;
etcp_update_log_name ( link - > etcp ) ;
link - > initialized = 1 ; // получен init response (client)
{ int old_state = link - > link_state ; link - > link_state = 3 ; etcp_fire_link_status_cbk ( link , old_state , link - > link_status ) ; }
{ int old_state = link - > link_state ; link - > link_state = LINK_STATE_CONNECTED ; etcp_fire_link_status_cbk ( link , old_state , link - > link_status ) ; }
if ( link - > init_timer ) {
uasync_cancel_timeout ( link - > etcp - > instance - > ua , link - > init_timer ) ;
link - > init_timer = NULL ;
@ -1876,7 +1939,7 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
// 66 - не удалось создать линк
struct ETCP_SOCKET * e_sock = ( struct ETCP_SOCKET * ) arg ;
if ( ! e_sock ) return ;
struct sockaddr_storage addr ;
uint8_t data [ PACKET_DATA_SIZE ] ;
socklen_t addr_len = sizeof ( addr ) ;
@ -1911,7 +1974,9 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
recv_len , ( unsigned long long ) link - > etcp - > crypto_ctx . rx_counter ) ;
sc_status_t dec_rc = sc_decrypt ( & link - > etcp - > crypto_ctx , data , recv_len , ( uint8_t * ) & pkt - > timestamp , & pkt_len ) ;
if ( ! dec_rc ) {
goto process_decrypted ;
int ec = etcp_packet_decrypted ( e_sock , pkt , link , pkt_len ) ;
if ( ec ) { errorcode = ec ; goto ec_fr ; }
return ;
}
DEBUG_DEBUG ( DEBUG_CATEGORY_ETCP , " etcp: DECRYPT FAIL on existing link. rc=%d link=%p log=%s from=%s sess=%d link_state=%d keepalive=%d enc_errs=%zu my_pub=%016llx peer_pub=%016llx seskey=%02x%02x%02x%02x " ,
dec_rc , link , link - > etcp - > log_name , sockaddr_storage_to_str ( & addr ) . str , link - > etcp - > crypto_ctx . session_ready ,
@ -2122,32 +2187,32 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
struct ETCP_LINK * existing_link = etcp_link_find_by_remote_id ( conn , req - > link_id ) ;
if ( ! existing_link ) {
existing_link = etcp_link_find_by_addr ( e_sock , & addr ) ;
if ( existing_link & & existing_link - > etcp = = conn ) {
if ( memcmp ( conn - > crypto_ctx . peer_public_key , sc . peer_public_key , SC_PUBKEY_SIZE ) ) {
DEBUG_WARN ( DEBUG_CATEGORY_CONNECTION , " [%s] link address match but pubkey mismatch, firing node_changed " , conn - > log_name ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_CRYPTO , " pubkey mismatch on reused link for node %016llx " , ( unsigned long long ) peer_id ) ;
conn - > callbacks_running = 1 ;
etcp_cbk_fire ( conn , ETCP_CBK_EVENT_NODE_CHANGED ) ;
conn - > callbacks_running = 0 ;
if ( existing_link & & existing_link - > etcp = = conn ) {
if ( memcmp ( conn - > crypto_ctx . peer_public_key , sc . peer_public_key , SC_PUBKEY_SIZE ) ) {
DEBUG_WARN ( DEBUG_CATEGORY_CONNECTION , " [%s] link address match but pubkey mismatch, firing node_changed " , conn - > log_name ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_CRYPTO , " pubkey mismatch on reused link for node %016llx " , ( unsigned long long ) peer_id ) ;
conn - > callbacks_running = 1 ;
etcp_cbk_fire ( conn , ETCP_CBK_EVENT_NODE_CHANGED ) ;
conn - > callbacks_running = 0 ;
errorcode = 67 ;
goto ec_fr ;
}
DEBUG_DEBUG ( DEBUG_CATEGORY_CONNECTION , " [%s] found existing outbound link by addr for incoming INIT, reusing link=%p " ,
conn - > log_name , existing_link ) ;
} else if ( existing_link ) {
struct ETCP_CONN * old_conn = existing_link - > etcp ;
DEBUG_WARN ( DEBUG_CATEGORY_CONNECTION , " [%s] conflicting link at %s belongs to %s, firing node_changed " ,
conn - > log_name , sockaddr_storage_to_str ( & addr ) . str , old_conn - > log_name ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_CRYPTO , " link address conflict for node %016llx, firing node_changed callbacks on %s " ,
( unsigned long long ) peer_id , old_conn - > log_name ) ;
old_conn - > callbacks_running = 1 ;
etcp_cbk_fire ( old_conn , ETCP_CBK_EVENT_NODE_CHANGED ) ;
old_conn - > callbacks_running = 0 ;
errorcode = 67 ;
goto ec_fr ;
} else {
existing_link = NULL ;
}
DEBUG_DEBUG ( DEBUG_CATEGORY_CONNECTION , " [%s] found existing outbound link by addr for incoming INIT, reusing link=%p " ,
conn - > log_name , existing_link ) ;
} else if ( existing_link ) {
struct ETCP_CONN * old_conn = existing_link - > etcp ;
DEBUG_WARN ( DEBUG_CATEGORY_CONNECTION , " [%s] conflicting link at %s belongs to %s, firing node_changed " ,
conn - > log_name , sockaddr_storage_to_str ( & addr ) . str , old_conn - > log_name ) ;
DEBUG_ERROR ( DEBUG_CATEGORY_CRYPTO , " link address conflict for node %016llx, firing node_changed callbacks on %s " ,
( unsigned long long ) peer_id , old_conn - > log_name ) ;
old_conn - > callbacks_running = 1 ;
etcp_cbk_fire ( old_conn , ETCP_CBK_EVENT_NODE_CHANGED ) ;
old_conn - > callbacks_running = 0 ;
errorcode = 67 ;
goto ec_fr ;
} else {
existing_link = NULL ;
}
}
uint8_t send_reset = 0 ;
@ -2256,7 +2321,9 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
etcp_conn_reinit ( conn , " session changed " ) ;
} }
}
link - > keepalive_interval = ( req - > keepalive [ 0 ] < < 8 ) | req - > keepalive [ 1 ] ;
uint16_t client_ka = ( req - > keepalive [ 0 ] < < 8 ) | req - > keepalive [ 1 ] ;
link - > peer_device_type = req - > device_type ;
link - > keepalive_interval = negotiate_keepalive ( e_sock - > instance - > client_type , e_sock - > instance - > keepalive_interval , req - > device_type , client_ka ) ;
link - > recovery_interval = ( ( req - > recovery [ 0 ] < < 8 ) | req - > recovery [ 1 ] ) * 100 ; // timebase в link, timebase/100 в кодограмме
if ( link - > keepalive_interval < 10 ) link - > keepalive_interval = 10 ;
DEBUG_DEBUG ( DEBUG_CATEGORY_KEEPALIVE , " set keepalive for link=%d " , link - > keepalive_interval ) ;
@ -2276,16 +2343,29 @@ void etcp_connections_read_callback_socket(socket_t sock, void* arg) {
return ;
process_decrypted :
ec_fr :
e_sock - > pkt_format_errors + + ;
if ( e_sock - > pkt_format_errors < 3 | | ( e_sock - > pkt_format_errors % 500 = = 0 ) )
DEBUG_WARN ( DEBUG_CATEGORY_ETCP , " error %d, from %s (count=%zu) " , errorcode , sockaddr_storage_to_str ( & addr ) . str , e_sock - > pkt_format_errors ) ;
e_sock - > errorcode = errorcode ;
memory_pool_free ( e_sock - > instance - > pkt_pool , pkt ) ;
return ;
}
int etcp_packet_decrypted ( struct ETCP_SOCKET * e_sock , struct ETCP_DGRAM * pkt ,
struct ETCP_LINK * link , size_t pkt_len ) {
DEBUG_TRACE ( DEBUG_CATEGORY_ETCP , " Decrypt ok - normal pkt " ) ;
if ( pkt_len < 3 ) { errorcode = 46 ; DEBUG_ERROR ( DEBUG_CATEGORY_ETCP , " decrypted packet too small, size=%zu " , pkt_len ) ; goto ec_fr ; }
if ( pkt_len < 3 ) { DEBUG_ERROR ( DEBUG_CATEGORY_ETCP , " decrypted packet too small, size=%zu " , pkt_len ) ; return 46 ; }
pkt - > data_len = pkt_len - 3 ;
pkt - > noencrypt_len = 0 ;
pkt - > link = link ;
if ( pkt - > data_len & & pkt - > data [ 0 ] ! = ETCP_KEEPALIVE ) {
DEBUG_DEBUG ( DEBUG_CATEGORY_DEBUG , " [%s] decrypt: code=%02x dlen=%u plen=%zu recv=%d sock=%p " ,
link - > etcp - > log_name , pkt - > data [ 0 ] , pkt - > data_len , pkt_len ,
link - > recv_keepalive , ( void * ) e_sock ) ;
}
link - > remote_keepalive = pkt - > flag_up ;
/* restore recv_keepalive BEFORE computing link_status = remote && local */
if ( link - > recv_keepalive ! = 1 ) {
link - > recv_keepalive = 1 ;
DEBUG_DEBUG ( DEBUG_CATEGORY_CONNECTION , " [%s] Link %d recv_keepalive restored to 1 (was 0) link_status=%d remote_ka=%d state=%d init=%d links_up=%d " ,
@ -2297,19 +2377,16 @@ process_decrypted:
if ( link - > link_status ! = was_up )
etcp_fire_link_status_cbk ( link , link - > link_state , was_up ) ;
if ( link - > link_status & & ! was_up & & link - > initialized ) {
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " [%s] Link %d status popped UP: recv_ka=%d remote_ka=%d state=%d init=%d → calling loadbalancer_link_ready " , link - > etcp - > log_name , link - > local_link_id , link - > recv_keepalive , link - > remote_keepalive , link - > link_state , link - > initialized ) ;
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " [%s] Link %d status popped UP: recv_ka=%d remote_ka=%d state=%d init=%d " , link - > etcp - > log_name , link - > local_link_id , link - > recv_keepalive , link - > remote_keepalive , link - > link_state , link - > initialized ) ;
loadbalancer_link_ready ( link ) ;
}
link - > last_recv_local_time = get_time_tb ( ) ;
link - > last_recv_timestamp = pkt - > timestamp ;
link - > last_recv_updated = 1 ;
// Count decrypted bytes
link - > total_decrypted + = pkt - > data_len ;
size_t offset = 0 ;
uint8_t pkt_code = pkt - > data [ offset + + ] ;
uint8_t pkt_code = pkt - > data [ 0 ] ;
if ( pkt_code = = ETCP_KEEPALIVE ) {
if ( pkt - > data_len > = 3 ) {
@ -2318,40 +2395,29 @@ process_decrypted:
}
link - > keepalive_recv_count + + ;
memory_pool_free ( e_sock - > instance - > pkt_pool , pkt ) ;
return ; // KA handled, nothing more to process
return 0 ;
}
if ( pkt_code = = ETCP_INIT_RESPONSE | | pkt_code = = ETCP_INIT_RESPONSE_NOINIT ) {
int ret = handle_init_response_client ( e_sock , pkt , link , pkt_code , pkt_len ) ;
if ( ret ) { errorcode = ret ; goto ec_fr ; }
return ;
if ( ret ) return ret ;
return 0 ;
}
if ( link - > link_state = = 2 ) { // из recovery получен нормальный пакет - восстанавливаем линк в нормальный режим
if ( link - > link_state = = LINK_STATE_TRY_RECONNECT ) { // 0 - just init, 1 - handshake, 2 - try reconnect, 3 - connected
start_keepalive_timer ( link ) ;
etcp_link_send_keepalive ( link ) ; // Start keepalive timer
{ int old_state = link - > link_state ; link - > link_state = 3 ; etcp_fire_link_status_cbk ( link , old_state , link - > link_status ) ; }
etcp_link_send_keepalive ( link ) ;
int old_state = link - > link_state ; link - > link_state = LINK_STATE_CONNECTED ;
etcp_fire_link_status_cbk ( link , old_state , link - > link_status ) ;
}
// log_dump("RECV decrypted:", pkt->data, pkt->data_len, link);
if ( link - > link_state = = 3 ) {
if ( link - > link_state = = LINK_STATE_CONNECTED ) {
if ( memory_pool_is_freed ( e_sock - > instance - > pkt_pool , pkt ) ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ETCP , " pkt=%p ALREADY FREED in pkt_pool — HALTING " , ( void * ) pkt ) ;
volatile int _halt = 1 ; while ( _halt ) { }
}
etcp_conn_input ( pkt ) ;
} else memory_pool_free ( e_sock - > instance - > pkt_pool , pkt ) ;
return ;
ec_fr :
e_sock - > pkt_format_errors + + ;
if ( e_sock - > pkt_format_errors < 3 | | ( e_sock - > pkt_format_errors % 500 = = 0 ) )
DEBUG_WARN ( DEBUG_CATEGORY_ETCP , " error %d, from %s (count=%zu) " , errorcode , sockaddr_storage_to_str ( & addr ) . str , e_sock - > pkt_format_errors ) ;
e_sock - > errorcode = errorcode ;
memory_pool_free ( e_sock - > instance - > pkt_pool , pkt ) ;
return ;
return 0 ;
}
// Initialize only sockets (servers for incoming connections)
@ -2424,7 +2490,7 @@ int init_sockets(struct UTUN_INSTANCE* instance) {
}
}
}
// TCP transport: create stcp_server instead of UDP socket
if ( server - > transport ) {
uint16_t port = 0 ;
@ -2469,7 +2535,7 @@ int init_sockets(struct UTUN_INSTANCE* instance) {
continue ;
}
success_count + + ;
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " Initialized server %s on %s (links: %d) " ,
server - > name , sockaddr_storage_to_str ( & server - > ip ) . str , queue_entry_count ( e_sock - > links_queue ) ) ;
server = server - > next ;