@ -1,9 +1,12 @@
// tun_if.c - TUN interface management implementation
// tun_if.c - Simplified TUN interface management implementation
# define _POSIX_C_SOURCE 200809L
# include "tun_if.h"
# include "config_parser.h"
# include "etcp.h"
# include "../lib/debug_config.h"
# include "../lib/u_async.h"
# include "etcp_connections.h"
# include "../lib/ll_queue.h"
# include "../lib/memory_pool.h"
# include <stdio.h>
# include <stdlib.h>
# include <string.h>
@ -46,7 +49,7 @@ static int parse_ip_mask(const char *ip_addr, struct in_addr *ip, struct in_addr
char ip_str [ INET_ADDRSTRLEN ] ;
char * slash = strchr ( ip_addr , ' / ' ) ;
if ( ! slash ) return - 1 ; // Require /mask
if ( ! slash ) return - 1 ;
size_t ip_len = slash - ip_addr ;
if ( ip_len > = sizeof ( ip_str ) ) return - 1 ;
@ -97,46 +100,8 @@ static int create_tun_device(char *ifname, size_t ifname_len) {
return fd ;
}
int tun_create ( struct tun_config * config ) {
if ( ! config ) {
errno = EINVAL ;
return - 1 ;
}
// Create TUN device
int fd = create_tun_device ( config - > ifname , sizeof ( config - > ifname ) ) ;
if ( fd < 0 ) {
return - 1 ;
}
config - > fd = fd ;
// Configure IP if specified
if ( config - > ip_addr [ 0 ] ! = ' \0 ' ) {
if ( tun_set_ip ( config - > ifname , config - > ip_addr ) < 0 ) {
close ( fd ) ;
return - 1 ;
}
}
// Set MTU if specified
if ( config - > mtu > 0 ) {
if ( tun_set_mtu ( config - > ifname , config - > mtu ) < 0 ) {
DEBUG_WARN ( DEBUG_CATEGORY_TUN , " Failed to set MTU %d on %s: %s " , config - > mtu , config - > ifname , strerror ( errno ) ) ;
}
}
// Bring interface up
if ( tun_set_up ( config - > ifname ) < 0 ) {
close ( fd ) ;
return - 1 ;
}
config - > is_up = 1 ;
return 0 ;
}
int tun_set_ip ( const char * ifname , const char * ip_addr ) {
// Set IP address on TUN interface
static int tun_set_ip ( const char * ifname , const char * ip_addr ) {
if ( ! ifname | | ! ip_addr ) {
errno = EINVAL ;
return - 1 ;
@ -167,7 +132,8 @@ int tun_set_ip(const char *ifname, const char *ip_addr) {
return 0 ;
}
int tun_set_up ( const char * ifname ) {
// Bring TUN interface up
static int tun_set_up ( const char * ifname ) {
if ( ! ifname ) {
errno = EINVAL ;
return - 1 ;
@ -186,7 +152,8 @@ int tun_set_up(const char *ifname) {
return 0 ;
}
int tun_set_mtu ( const char * ifname , int mtu ) {
// Set MTU on TUN interface
static int tun_set_mtu ( const char * ifname , int mtu ) {
if ( ! ifname | | mtu < = 0 ) {
errno = EINVAL ;
return - 1 ;
@ -201,119 +168,228 @@ int tun_set_mtu(const char *ifname, int mtu) {
return 0 ;
}
ssize_t tun_read ( int fd , uint8_t * buffer , size_t size ) {
if ( fd < 0 | | ! buffer | | size = = 0 ) {
errno = EINVAL ;
return - 1 ;
}
// Internal read callback - called by uasync when data available on TUN
static void tun_read_callback ( int fd , void * user_arg ) {
struct tun_if * tun = ( struct tun_if * ) user_arg ;
uint8_t buffer [ TUN_MAX_PACKET_SIZE ] ;
ssize_t nread = read ( fd , buffer , size ) ;
// Read from TUN device
ssize_t nread = read ( fd , buffer , sizeof ( buffer ) ) ;
if ( nread < 0 ) {
perror ( " tun_read " ) ;
if ( errno = = EINTR ) return ;
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to read from TUN device %s: %s " , tun - > ifname , strerror ( errno ) ) ;
tun - > read_errors + + ;
return ;
}
return nread ;
}
if ( nread = = 0 ) return ;
ssize_t tun_write ( int fd , const uint8_t * buffer , size_t size ) {
if ( fd < 0 | | ! buffer | | size = = 0 ) {
errno = EINVAL ;
return - 1 ;
// Allocate packet data
uint8_t * packet_data = malloc ( nread ) ;
if ( ! packet_data ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to allocate packet data (size=%zd) " , nread ) ;
tun - > read_errors + + ;
return ;
}
memcpy ( packet_data , buffer , nread ) ;
// Allocate ETCP_FRAGMENT from pool
struct ETCP_FRAGMENT * pkt = ( struct ETCP_FRAGMENT * ) queue_entry_new_from_pool ( tun - > pool ) ;
if ( ! pkt ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to allocate ETCP_FRAGMENT from pool " ) ;
free ( packet_data ) ;
tun - > read_errors + + ;
return ;
}
ssize_t nwritten = write ( fd , buffer , size ) ;
if ( nwritten < 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to write to TUN device fd=%d: %s " , fd , strerror ( errno ) ) ;
// Initialize fragment
pkt - > seq = 0 ;
pkt - > timestamp = 0 ;
pkt - > ll . dgram = packet_data ;
pkt - > ll . len = nread ;
// Add to input queue
if ( queue_data_put ( tun - > input_queue , ( struct ll_entry * ) pkt , 0 ) ! = 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to add packet to input queue " ) ;
free ( packet_data ) ;
memory_pool_free ( tun - > pool , pkt ) ;
tun - > read_errors + + ;
return ;
}
return nwritten ;
// Update statistics
tun - > bytes_read + = nread ;
tun - > packets_read + + ;
DEBUG_DEBUG ( DEBUG_CATEGORY_TUN , " Read %zd bytes from TUN %s " , nread , tun - > ifname ) ;
}
void tun_close ( struct tun_config * config ) {
if ( ! config ) return ;
struct tun_if * tun_init ( struct UASYNC * ua , struct utun_config * config ) {
if ( ! ua | | ! config ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Invalid arguments: ua=%p, config=%p " , ua , config ) ;
return NULL ;
}
if ( config - > fd > = 0 ) {
close ( config - > fd ) ;
config - > fd = - 1 ;
// Allocate tun_if structure
struct tun_if * tun = calloc ( 1 , sizeof ( struct tun_if ) ) ;
if ( ! tun ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to allocate tun_if " ) ;
return NULL ;
}
config - > is_up = 0 ;
}
tun - > ua = ua ;
tun - > fd = - 1 ;
int tun_get_config ( const char * ifname , struct tun_config * config ) {
if ( ! ifname | | ! config ) {
errno = EINVAL ;
return - 1 ;
// Get interface name from config (or empty for auto)
const char * ifname = config - > global . tun_ifname ;
if ( ifname & & ifname [ 0 ] ! = ' \0 ' ) {
strncpy ( tun - > ifname , ifname , sizeof ( tun - > ifname ) - 1 ) ;
}
// TODO: Implement reading current interface configuration
// This would require ioctl SIOCGIFADDR, SIOCGIFNETMASK, etc.
// Create TUN device
tun - > fd = create_tun_device ( tun - > ifname , sizeof ( tun - > ifname ) ) ;
if ( tun - > fd < 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to create TUN device " ) ;
free ( tun ) ;
return NULL ;
}
memset ( config , 0 , sizeof ( * config ) ) ;
strncpy ( config - > ifname , ifname , sizeof ( config - > ifname ) - 1 ) ;
config - > fd = - 1 ;
// Build IP address string from config
char ip_buffer [ INET_ADDRSTRLEN ] ;
char tun_ip_str [ 64 ] ;
if ( config - > global . tun_ip . family = = AF_INET ) {
inet_ntop ( AF_INET , & config - > global . tun_ip . addr . v4 , ip_buffer , sizeof ( ip_buffer ) ) ;
} else {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Only IPv4 is supported for TUN " ) ;
close ( tun - > fd ) ;
free ( tun ) ;
return NULL ;
}
return 0 ;
}
# ifdef __linux__
snprintf ( tun_ip_str , sizeof ( tun_ip_str ) , " %s/32 " , ip_buffer ) ;
# elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
snprintf ( tun_ip_str , sizeof ( tun_ip_str ) , " %s " , ip_buffer ) ;
# else
snprintf ( tun_ip_str , sizeof ( tun_ip_str ) , " %s/32 " , ip_buffer ) ;
# endif
// Configure IP address
if ( tun_set_ip ( tun - > ifname , tun_ip_str ) < 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to set TUN IP: %s " , tun_ip_str ) ;
close ( tun - > fd ) ;
free ( tun ) ;
return NULL ;
}
// Set MTU to 1500 (default)
int mtu = config - > global . mtu > 0 ? config - > global . mtu : TUN_MTU_DEFAULT ;
if ( tun_set_mtu ( tun - > ifname , mtu ) < 0 ) {
DEBUG_WARN ( DEBUG_CATEGORY_TUN , " Failed to set MTU %d on %s: %s " , mtu , tun - > ifname , strerror ( errno ) ) ;
}
// Bring interface up
if ( tun_set_up ( tun - > ifname ) < 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to bring up TUN interface %s " , tun - > ifname ) ;
close ( tun - > fd ) ;
free ( tun ) ;
return NULL ;
}
// Create memory pool for ETCP_FRAGMENT
tun - > pool = memory_pool_init ( sizeof ( struct ETCP_FRAGMENT ) ) ;
if ( ! tun - > pool ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to create memory pool " ) ;
close ( tun - > fd ) ;
free ( tun ) ;
return NULL ;
}
// Create input queue
tun - > input_queue = queue_new ( ua , 0 ) ; // hash_size=0 - no ID lookup needed
if ( ! tun - > input_queue ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to create input queue " ) ;
memory_pool_destroy ( tun - > pool ) ;
close ( tun - > fd ) ;
free ( tun ) ;
return NULL ;
}
// Register TUN socket with uasync
tun - > socket_id = uasync_add_socket ( ua , tun - > fd , tun_read_callback , NULL , NULL , tun ) ;
if ( ! tun - > socket_id ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to register TUN socket with uasync " ) ;
queue_free ( tun - > input_queue ) ;
memory_pool_destroy ( tun - > pool ) ;
close ( tun - > fd ) ;
free ( tun ) ;
return NULL ;
}
DEBUG_INFO ( DEBUG_CATEGORY_TUN , " TUN interface initialized: %s (fd=%d, IP=%s, MTU=%d) " ,
tun - > ifname , tun - > fd , tun_ip_str , mtu ) ;
// Extract destination IPv4 address from packet
static uint32_t get_dest_ip ( const uint8_t * packet , size_t len ) {
if ( len < 20 ) return 0 ; // Minimum IPv4 header size
// Check IP version (first nibble)
uint8_t version = ( packet [ 0 ] > > 4 ) & 0x0F ;
if ( version ! = 4 ) return 0 ;
// Destination IP is at offset 16
uint32_t dest_ip ;
memcpy ( & dest_ip , packet + 16 , 4 ) ;
return dest_ip ;
return tun ;
}
// Callback for TUN device read events
void tun_read_callback ( int fd , void * user_arg ) {
struct UTUN_INSTANCE * instance = ( struct UTUN_INSTANCE * ) user_arg ;
uint8_t buffer [ MAX_PACKET_SIZE ] ;
void tun_close ( struct tun_if * tun ) {
if ( ! tun ) return ;
// Read from TUN device
ssize_t nread = tun_read ( fd , buffer , sizeof ( buffer ) ) ;
if ( nread < 0 ) {
if ( errno = = EINTR ) return ;
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to read from TUN device %s: %s " , instance - > tun . ifname , strerror ( errno ) ) ;
return ;
DEBUG_INFO ( DEBUG_CATEGORY_TUN , " Closing TUN interface: %s " , tun - > ifname ) ;
// Unregister socket from uasync
if ( tun - > socket_id & & tun - > ua ) {
uasync_remove_socket ( tun - > ua , tun - > socket_id ) ;
tun - > socket_id = NULL ;
}
// Drain and free all packets from input queue
if ( tun - > input_queue ) {
struct ETCP_FRAGMENT * pkt ;
while ( ( pkt = ( struct ETCP_FRAGMENT * ) queue_data_get ( tun - > input_queue ) ) ! = NULL ) {
if ( pkt - > ll . dgram ) {
free ( pkt - > ll . dgram ) ;
}
memory_pool_free ( tun - > pool , pkt ) ;
}
queue_free ( tun - > input_queue ) ;
tun - > input_queue = NULL ;
}
if ( nread > 0 ) {
// Route packet based on destination IP
uint32_t dest_ip = get_dest_ip ( buffer , nread ) ;
// ... (rest of the routing logic)
// Destroy memory pool
if ( tun - > pool ) {
memory_pool_destroy ( tun - > pool ) ;
tun - > pool = NULL ;
}
// Close file descriptor
if ( tun - > fd > = 0 ) {
close ( tun - > fd ) ;
tun - > fd = - 1 ;
}
free ( tun ) ;
}
// Register sockets with uasync
int utun_instance_register_sockets ( struct UTUN_INSTANCE * instance ) {
if ( ! instance | | ! instance - > ua | | instance - > tun . fd < 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Invalid instance or TUN fd " ) ;
ssize_t tun_write ( struct tun_if * tun , const uint8_t * buf , size_t len ) {
if ( ! tun | | tun - > fd < 0 | | ! buf | | len = = 0 ) {
if ( tun ) tun - > write_errors + + ;
errno = EINVAL ;
return - 1 ;
}
// Register TUN file descriptor
instance - > tun_socket_id = uasync_add_socket ( instance - > ua , instance - > tun . fd ,
tun_read_callback , NULL , NULL , instance ) ;
if ( ! instance - > tun_socket_id ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to register TUN socket " ) ;
ssize_t nwritten = write ( tun - > fd , buf , len ) ;
if ( nwritten < 0 ) {
DEBUG_ERROR ( DEBUG_CATEGORY_TUN , " Failed to write to TUN device %s: %s " , tun - > ifname , strerror ( errno ) ) ;
tun - > write_errors + + ;
return - 1 ;
}
DEBUG_INFO ( DEBUG_CATEGORY_TUN , " Registered TUN socket (fd=%d) " , instance - > tun . fd ) ;
return 0 ;
}
tun - > bytes_written + = nwritten ;
tun - > packets_written + + ;
// Unregister sockets
void utun_instance_unregister_sockets ( struct UTUN_INSTANCE * instance ) {
if ( ! instance | | ! instance - > ua ) return ;
DEBUG_DEBUG ( DEBUG_CATEGORY_TUN , " Wrote %zd bytes to TUN %s " , nwritten , tun - > ifname ) ;
if ( instance - > tun_socket_id ) {
uasync_remove_socket ( instance - > ua , instance - > tun_socket_id ) ;
instance - > tun_socket_id = NULL ;
DEBUG_INFO ( DEBUG_CATEGORY_TUN , " Unregistered TUN socket: %s " , instance - > tun . ifname ) ;
}
}
return nwritten ;
}