@ -655,6 +655,8 @@ static void etcp_connections_read_callback(int fd, void* arg) {
uint8_t id [ 8 ] ;
uint8_t mtu [ 2 ] ;
uint8_t link_id ;
uint8_t peer_ipv4 [ 4 ] ;
uint8_t peer_port [ 2 ] ;
} * ack_repl_hdr = ( void * ) & pkt - > data [ 0 ] ;
ack_repl_hdr - > code + = 1 ;
memcpy ( ack_repl_hdr - > id , & e_sock - > instance - > node_id , 8 ) ;
@ -662,6 +664,18 @@ static void etcp_connections_read_callback(int fd, void* arg) {
ack_repl_hdr - > mtu [ 0 ] = mtu > > 8 ;
ack_repl_hdr - > mtu [ 1 ] = mtu ;
ack_repl_hdr - > link_id = link - > local_link_id ;
// Add client's IP:port (so client behind NAT can know its external address)
if ( addr . ss_family = = AF_INET ) {
struct sockaddr_in * sin = ( struct sockaddr_in * ) & addr ;
memcpy ( ack_repl_hdr - > peer_ipv4 , & sin - > sin_addr . s_addr , 4 ) ;
uint16_t port = ntohs ( sin - > sin_port ) ;
ack_repl_hdr - > peer_port [ 0 ] = port > > 8 ;
ack_repl_hdr - > peer_port [ 1 ] = port & 0xFF ;
} else {
// For IPv6, set to 0 (not supported for NAT traversal)
memset ( ack_repl_hdr - > peer_ipv4 , 0 , 4 ) ;
memset ( ack_repl_hdr - > peer_port , 0 , 2 ) ;
}
pkt - > data_len = sizeof ( * ack_repl_hdr ) ;
pkt - > noencrypt_len = 0 ;
pkt - > link = link ;
@ -707,6 +721,54 @@ static void etcp_connections_read_callback(int fd, void* arg) {
}
link - > mtu = ( pkt - > data [ offset + + ] < < 8 ) | pkt - > data [ offset + + ] ;
link - > remote_link_id = pkt - > data [ offset + + ] ;
// Parse NAT IP:port from response (new format includes 4+2 bytes)
if ( pkt_len > = 18 ) {
uint32_t new_nat_ip = ( pkt - > data [ offset ] < < 24 ) | ( pkt - > data [ offset + 1 ] < < 16 ) |
( pkt - > data [ offset + 2 ] < < 8 ) | pkt - > data [ offset + 3 ] ;
offset + = 4 ;
uint16_t new_nat_port = ( pkt - > data [ offset ] < < 8 ) | pkt - > data [ offset + 1 ] ;
offset + = 2 ;
// Check if NAT address changed
if ( link - > nat_ip = = 0 & & link - > nat_port = = 0 ) {
// First time receiving NAT info
link - > nat_ip = new_nat_ip ;
link - > nat_port = new_nat_port ;
char ip_str [ INET_ADDRSTRLEN ] ;
struct in_addr addr ;
addr . s_addr = htonl ( new_nat_ip ) ;
inet_ntop ( AF_INET , & addr , ip_str , sizeof ( ip_str ) ) ;
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " [%s] NAT address initialized: %s:%u " ,
link - > etcp - > log_name , ip_str , new_nat_port ) ;
} else if ( link - > nat_ip ! = new_nat_ip | | link - > nat_port ! = new_nat_port ) {
// NAT address changed
char old_ip_str [ INET_ADDRSTRLEN ] , new_ip_str [ INET_ADDRSTRLEN ] ;
struct in_addr old_addr , new_addr ;
old_addr . s_addr = htonl ( link - > nat_ip ) ;
new_addr . s_addr = htonl ( new_nat_ip ) ;
inet_ntop ( AF_INET , & old_addr , old_ip_str , sizeof ( old_ip_str ) ) ;
inet_ntop ( AF_INET , & new_addr , new_ip_str , sizeof ( new_ip_str ) ) ;
link - > nat_ip = new_nat_ip ;
link - > nat_port = new_nat_port ;
link - > nat_changes_count + + ;
DEBUG_INFO ( DEBUG_CATEGORY_CONNECTION , " [%s] NAT address changed: %s:%u -> %s:%u (change #%u) " ,
link - > etcp - > log_name , old_ip_str , link - > nat_port , new_ip_str , new_nat_port ,
link - > nat_changes_count ) ;
} else {
// NAT address unchanged
link - > nat_hits_count + + ;
DEBUG_DEBUG ( DEBUG_CATEGORY_CONNECTION , " [%s] NAT address unchanged (%u matches) " ,
link - > etcp - > log_name , link - > nat_hits_count ) ;
}
} else {
// Legacy format without NAT info
DEBUG_DEBUG ( DEBUG_CATEGORY_CONNECTION , " [%s] Received legacy INIT_RESPONSE without NAT info " ,
link - > etcp - > log_name ) ;
}
if ( offset > pkt_len ) { errorcode = 13 ; DEBUG_ERROR ( DEBUG_CATEGORY_ETCP , " etcp_connections_read_callback: packet parsing overflow, offset=%zu, pkt_len=%zu " , offset , pkt_len ) ; goto ec_fr ; }
// DEBUG_INFO(DEBUG_CATEGORY_CONNECTION, "Received INIT_RESPONSE from server_node_id=%llu, mtu=%d", (unsigned long long)server_node_id, link->mtu);