@ -3,6 +3,7 @@
# include "route_lib.h"
# include "tun_if.h"
# include "etcp.h"
# include "etcp_api.h"
# include "pkt_normalizer.h"
# include "utun_instance.h"
# include "../lib/ll_queue.h"
@ -17,6 +18,9 @@
# define IP_HDR_DST_ADDR_OFFSET 16
# define IP_HDR_MIN_SIZE 20
// ETCP packet ID for routing data
# define ETCP_ID_DATA 0x00
// Extract destination IP from IPv4 packet
// Returns 0 if not IPv4 or packet too small
static uint32_t extract_dst_ip ( uint8_t * data , size_t len ) {
@ -45,78 +49,100 @@ static uint32_t extract_dst_ip(uint8_t* data, size_t len) {
return dst_ip ; // Keep in network byte order
}
// Callback for packets from ETCP normalizer output queue
static void routing_pkt_from_etcp_cb ( struct ll_queue * q , void * arg ) {
struct ETCP_CONN * etcp = ( struct ETCP_CONN * ) arg ;
if ( ! etcp | | ! etcp - > instance ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " routing_pkt_from_etcp_cb: invalid etcp or instance " ) ;
// Callback for packets from ETCP (via etcp_bind id=0)
// Format: <id 1 byte> <ip_packet ...>
static void routing_pkt_from_etcp_cb ( struct ETCP_CONN * conn , struct ll_entry * entry ) {
if ( ! conn | | ! entry ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " routing_pkt_from_etcp_cb: invalid arguments " ) ;
if ( entry ) {
queue_entry_free ( entry ) ;
queue_dgram_free ( entry ) ;
}
return ;
}
struct UTUN_INSTANCE * instance = conn - > instance ;
if ( ! instance ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " routing_pkt_from_etcp_cb: connection has no instance " ) ;
queue_entry_free ( entry ) ;
queue_dgram_free ( entry ) ;
return ;
}
struct UTUN_INSTANCE * instance = etcp - > instance ;
if ( ! instance - > tun ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " routing_pkt_from_etcp_cb: no TUN interface " ) ;
queue_entry_free ( entry ) ;
queue_dgram_free ( entry ) ;
return ;
}
struct ll_entry * entry = queue_data_get ( q ) ;
while ( entry ) {
if ( entry - > dgram & & entry - > len > 0 ) {
// Check MTU
if ( entry - > len > TUN_MAX_PACKET_SIZE ) {
DEBUG_WARN ( DEBUG_CATEGORY_ROUTING , " Packet too large: %zu bytes (max %d) " ,
entry - > len , TUN_MAX_PACKET_SIZE ) ;
} else {
// Extract destination IP for future routing (currently ignored)
uint32_t dst_ip = extract_dst_ip ( entry - > dgram , entry - > len ) ;
if ( dst_ip ! = 0 ) {
char ip_str [ INET_ADDRSTRLEN ] ;
inet_ntop ( AF_INET , & dst_ip , ip_str , sizeof ( ip_str ) ) ;
DEBUG_DEBUG ( DEBUG_CATEGORY_ROUTING , " Packet from ETCP to %s " , ip_str ) ;
}
// Allocate ETCP_FRAGMENT for TUN input_queue
struct ETCP_FRAGMENT * pkt = ( struct ETCP_FRAGMENT * ) queue_entry_new_from_pool ( instance - > tun - > pool ) ;
if ( ! pkt ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " Failed to allocate ETCP_FRAGMENT for TUN " ) ;
} else {
// Allocate packet data (TUN will free it)
uint8_t * packet_data = malloc ( entry - > len ) ;
if ( ! packet_data ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " Failed to allocate packet data " ) ;
memory_pool_free ( instance - > tun - > pool , pkt ) ;
} else {
memcpy ( packet_data , entry - > dgram , entry - > len ) ;
pkt - > seq = 0 ;
pkt - > timestamp = 0 ;
pkt - > ll . dgram = packet_data ;
pkt - > ll . len = entry - > len ;
// Put to TUN input_queue
if ( queue_data_put ( instance - > tun - > input_queue , ( struct ll_entry * ) pkt , 0 ) ! = 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " Failed to put packet to TUN input_queue " ) ;
free ( packet_data ) ;
memory_pool_free ( instance - > tun - > pool , pkt ) ;
} else {
DEBUG_DEBUG ( DEBUG_CATEGORY_ROUTING , " Forwarded %zu bytes from ETCP to TUN " , entry - > len ) ;
}
}
}
}
// Free original entry data
free ( entry - > dgram ) ;
}
// Free entry structure
// Check packet data
if ( ! entry - > dgram | | entry - > len < 2 ) {
DEBUG_WARN ( DEBUG_CATEGORY_ROUTING , " routing_pkt_from_etcp_cb: packet too small or no data " ) ;
queue_entry_free ( entry ) ;
// Get next packet
entry = queue_data_get ( q ) ;
queue_dgram_free ( entry ) ;
return ;
}
// Skip ID byte, extract IP packet (offset 1)
uint8_t * ip_data = entry - > dgram + 1 ;
size_t ip_len = entry - > len - 1 ;
// Check MTU
if ( ip_len > TUN_MAX_PACKET_SIZE ) {
DEBUG_WARN ( DEBUG_CATEGORY_ROUTING , " Packet too large: %zu bytes (max %d) " ,
ip_len , TUN_MAX_PACKET_SIZE ) ;
queue_entry_free ( entry ) ;
queue_dgram_free ( entry ) ;
return ;
}
// Log destination IP
uint32_t dst_ip = extract_dst_ip ( ip_data , ip_len ) ;
if ( dst_ip ! = 0 ) {
char ip_str [ INET_ADDRSTRLEN ] ;
inet_ntop ( AF_INET , & dst_ip , ip_str , sizeof ( ip_str ) ) ;
DEBUG_DEBUG ( DEBUG_CATEGORY_ROUTING , " Packet from ETCP to %s " , ip_str ) ;
}
// Allocate ETCP_FRAGMENT for TUN input_queue
struct ETCP_FRAGMENT * pkt = ( struct ETCP_FRAGMENT * ) queue_entry_new_from_pool ( instance - > tun - > pool ) ;
if ( ! pkt ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " Failed to allocate ETCP_FRAGMENT for TUN " ) ;
queue_entry_free ( entry ) ;
queue_dgram_free ( entry ) ;
return ;
}
// Allocate packet data (TUN will free it)
uint8_t * packet_data = malloc ( ip_len ) ;
if ( ! packet_data ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " Failed to allocate packet data " ) ;
memory_pool_free ( instance - > tun - > pool , pkt ) ;
queue_entry_free ( entry ) ;
queue_dgram_free ( entry ) ;
return ;
}
memcpy ( packet_data , ip_data , ip_len ) ;
pkt - > seq = 0 ;
pkt - > timestamp = 0 ;
pkt - > ll . dgram = packet_data ;
pkt - > ll . len = ip_len ;
// Put to TUN input_queue
if ( queue_data_put ( instance - > tun - > input_queue , ( struct ll_entry * ) pkt , 0 ) ! = 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " Failed to put packet to TUN input_queue " ) ;
free ( packet_data ) ;
memory_pool_free ( instance - > tun - > pool , pkt ) ;
} else {
DEBUG_DEBUG ( DEBUG_CATEGORY_ROUTING , " Forwarded %zu bytes from ETCP to TUN " , ip_len ) ;
}
queue_resume_callback ( q ) ;
// Free original entry from ETCP
queue_entry_free ( entry ) ;
queue_dgram_free ( entry ) ;
}
// Callback for packets from TUN output queue
@ -128,25 +154,94 @@ static void routing_pkt_from_tun_cb(struct ll_queue* q, void* arg) {
return ;
}
// For now, just drain the queue (routing to ETCP will be implemented later)
if ( ! instance - > rt ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " routing_pkt_from_tun_cb: no route table " ) ;
return ;
}
struct ETCP_FRAGMENT * pkt = ( struct ETCP_FRAGMENT * ) queue_data_get ( instance - > tun - > output_queue ) ;
while ( pkt ) {
if ( pkt - > ll . dgram & & pkt - > ll . len > 0 ) {
// Extract destination IP for future routing
// Extract destination IP for routing
uint32_t dst_ip = extract_dst_ip ( pkt - > ll . dgram , pkt - > ll . len ) ;
if ( dst_ip ! = 0 ) {
char ip_str [ INET_ADDRSTRLEN ] ;
inet_ntop ( AF_INET , & dst_ip , ip_str , sizeof ( ip_str ) ) ;
DEBUG_DEBUG ( DEBUG_CATEGORY_ROUTING , " Packet from TUN to %s (dropped, routing not implemented yet) " , ip_str ) ;
if ( dst_ip = = 0 ) {
DEBUG_WARN ( DEBUG_CATEGORY_ROUTING , " Failed to extract destination IP, dropping packet " ) ;
free ( pkt - > ll . dgram ) ;
memory_pool_free ( instance - > tun - > pool , pkt ) ;
pkt = ( struct ETCP_FRAGMENT * ) queue_data_get ( instance - > tun - > output_queue ) ;
continue ;
}
char ip_str [ INET_ADDRSTRLEN ] ;
inet_ntop ( AF_INET , & dst_ip , ip_str , sizeof ( ip_str ) ) ;
// Lookup route in routing table
struct ROUTE_ARRAY * routes = route_table_lookup ( instance - > rt , dst_ip ) ;
if ( ! routes | | routes - > routes = = 0 ) {
DEBUG_WARN ( DEBUG_CATEGORY_ROUTING , " No route to %s, dropping packet " , ip_str ) ;
free ( pkt - > ll . dgram ) ;
memory_pool_free ( instance - > tun - > pool , pkt ) ;
pkt = ( struct ETCP_FRAGMENT * ) queue_data_get ( instance - > tun - > output_queue ) ;
continue ;
}
// Use first (best) route
struct ETCP_CONN * conn = routes - > entries [ 0 ] - > next_hop ;
if ( ! conn ) {
DEBUG_WARN ( DEBUG_CATEGORY_ROUTING , " Route to %s has no next_hop, dropping packet " , ip_str ) ;
free ( pkt - > ll . dgram ) ;
memory_pool_free ( instance - > tun - > pool , pkt ) ;
pkt = ( struct ETCP_FRAGMENT * ) queue_data_get ( instance - > tun - > output_queue ) ;
continue ;
}
// Check connection has normalizer
if ( ! conn - > normalizer ) {
DEBUG_WARN ( DEBUG_CATEGORY_ROUTING , " Connection for %s has no normalizer, dropping packet " , ip_str ) ;
free ( pkt - > ll . dgram ) ;
memory_pool_free ( instance - > tun - > pool , pkt ) ;
pkt = ( struct ETCP_FRAGMENT * ) queue_data_get ( instance - > tun - > output_queue ) ;
continue ;
}
// Create ll_entry with ID prefix for ETCP
// Format: <id 1 byte> <ip_packet ...>
size_t etcp_data_len = 1 + pkt - > ll . len ;
struct ll_entry * entry = ll_alloc_lldgram ( etcp_data_len ) ;
if ( ! entry ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " Failed to allocate entry for ETCP send " ) ;
free ( pkt - > ll . dgram ) ;
memory_pool_free ( instance - > tun - > pool , pkt ) ;
pkt = ( struct ETCP_FRAGMENT * ) queue_data_get ( instance - > tun - > output_queue ) ;
continue ;
}
// Free packet data
// Set ID byte and copy IP packet
entry - > dgram [ 0 ] = ETCP_ID_DATA ;
memcpy ( entry - > dgram + 1 , pkt - > ll . dgram , pkt - > ll . len ) ;
entry - > len = etcp_data_len ;
// Send via etcp_send
if ( etcp_send ( conn , entry ) ! = 0 ) {
DEBUG_WARN ( DEBUG_CATEGORY_ROUTING , " etcp_send failed for %s " , ip_str ) ;
queue_entry_free ( entry ) ;
queue_dgram_free ( entry ) ;
} else {
DEBUG_DEBUG ( DEBUG_CATEGORY_ROUTING , " Forwarded packet to %s via ETCP conn [%s] " ,
ip_str , conn - > log_name ) ;
}
// Free original TUN packet
free ( pkt - > ll . dgram ) ;
memory_pool_free ( instance - > tun - > pool , pkt ) ;
} else {
// Empty packet - just free structure
if ( pkt - > ll . dgram ) {
free ( pkt - > ll . dgram ) ;
}
memory_pool_free ( instance - > tun - > pool , pkt ) ;
}
// Free fragment structure
memory_pool_free ( instance - > tun - > pool , pkt ) ;
// Get next packet
pkt = ( struct ETCP_FRAGMENT * ) queue_data_get ( instance - > tun - > output_queue ) ;
}
@ -166,6 +261,14 @@ int routing_create(struct UTUN_INSTANCE* instance) {
return - 1 ;
}
// Bind ID=0 for receiving data packets from ETCP
if ( etcp_bind ( instance , ETCP_ID_DATA , routing_pkt_from_etcp_cb ) ! = 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " Failed to bind ETCP ID=0 " ) ;
route_table_destroy ( instance - > rt ) ;
instance - > rt = NULL ;
return - 1 ;
}
DEBUG_INFO ( DEBUG_CATEGORY_ROUTING , " Routing module initialized for instance " ) ;
return 0 ;
@ -177,6 +280,9 @@ void routing_destroy(struct UTUN_INSTANCE* instance) {
DEBUG_INFO ( DEBUG_CATEGORY_ROUTING , " Destroying routing module " ) ;
// Unbind ETCP ID=0
etcp_unbind ( instance , ETCP_ID_DATA ) ;
// Clean up route table if exists
if ( instance - > rt ) {
route_table_destroy ( instance - > rt ) ;
@ -184,46 +290,18 @@ void routing_destroy(struct UTUN_INSTANCE* instance) {
}
}
// Register ETCP connection with routing
// Register ETCP connection with routing (deprecated, kept for compatibility)
void routing_add_conn ( struct ETCP_CONN * etcp ) {
if ( ! etcp ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " routing_add_conn: etcp is NULL " ) ;
return ;
}
if ( ! etcp - > instance ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " routing_add_conn: etcp has no instance " ) ;
return ;
}
if ( ! etcp - > normalizer ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " routing_add_conn: ETCP has no normalizer " ) ;
return ;
}
struct PKTNORM * pn = ( struct PKTNORM * ) etcp - > normalizer ;
// Set callback on normalizer output queue - pass etcp as arg
// queue_set_callback(pn->output, routing_pkt_from_etcp_cb, etcp);
DEBUG_INFO ( DEBUG_CATEGORY_ROUTING , " Added ETCP connection to routing " ) ;
( void ) etcp ;
// No-op: connections are now handled via routing table entries
DEBUG_DEBUG ( DEBUG_CATEGORY_ROUTING , " routing_add_conn: deprecated, no action taken " ) ;
}
// Unregister ETCP connection from routing
// Unregister ETCP connection from routing (deprecated, kept for compatibility)
void routing_del_conn ( struct ETCP_CONN * etcp ) {
if ( ! etcp ) {
DEBUG_ERROR ( DEBUG_CATEGORY_ROUTING , " routing_del_conn: etcp is NULL " ) ;
return ;
}
if ( ! etcp - > normalizer ) {
return ; // Nothing to do
}
// Note: ll_queue doesn't have a direct way to clear callback
// The callback will be ignored when etcp is freed
DEBUG_INFO ( DEBUG_CATEGORY_ROUTING , " Removed ETCP connection from routing " ) ;
( void ) etcp ;
// No-op: connections are now handled via routing table entries
DEBUG_DEBUG ( DEBUG_CATEGORY_ROUTING , " routing_del_conn: deprecated, no action taken " ) ;
}
// Set TUN interface for routing