Simplify tun_if: unified init, write, close API with queue-based reads
- New struct tun_if with internal queue for incoming packets - Single tun_init() does everything: create TUN, set MTU=1500, up, register in uasync - tun_write() for outgoing packets - tun_close() cleans up everything including queue - Removed: tun_create, tun_set_ip, tun_set_up, tun_set_mtu, tun_read, tun_get_config - Removed: utun_instance_register/unregister_sockets (now internal) - Updated utun_instance to use new tun_if* pointer - Updated test_etcp_two_instances for new API
This commit is contained in:
1 parent
2e48f9a111
commit
5a7107b855
25 files changed
+302
-346
No files matched your search
+220
-144
@@ -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;
|
||||
}
|
||||
|
||||
ssize_t nread = read(fd, buffer, size);
|
||||
if (nread < 0) {
|
||||
perror("tun_read");
|
||||
}
|
||||
|
||||
return nread;
|
||||
}
|
||||
|
||||
ssize_t tun_write(int fd, const uint8_t *buffer, size_t size) {
|
||||
if (fd < 0 || !buffer || size == 0) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
void tun_close(struct tun_config *config) {
|
||||
if (!config) return;
|
||||
|
||||
if (config->fd >= 0) {
|
||||
close(config->fd);
|
||||
config->fd = -1;
|
||||
}
|
||||
|
||||
config->is_up = 0;
|
||||
}
|
||||
|
||||
int tun_get_config(const char *ifname, struct tun_config *config) {
|
||||
if (!ifname || !config) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// TODO: Implement reading current interface configuration
|
||||
// This would require ioctl SIOCGIFADDR, SIOCGIFNETMASK, etc.
|
||||
|
||||
memset(config, 0, sizeof(*config));
|
||||
strncpy(config->ifname, ifname, sizeof(config->ifname) - 1);
|
||||
config->fd = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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];
|
||||
// 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];
|
||||
|
||||
// Read from TUN device
|
||||
ssize_t nread = tun_read(fd, buffer, sizeof(buffer));
|
||||
ssize_t nread = 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));
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to read from TUN device %s: %s", tun->ifname, strerror(errno));
|
||||
tun->read_errors++;
|
||||
return;
|
||||
}
|
||||
|
||||
if (nread > 0) {
|
||||
// Route packet based on destination IP
|
||||
uint32_t dest_ip = get_dest_ip(buffer, nread);
|
||||
// ... (rest of the routing logic)
|
||||
if (nread == 0) return;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Update statistics
|
||||
tun->bytes_read += nread;
|
||||
tun->packets_read++;
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_TUN, "Read %zd bytes from TUN %s", nread, tun->ifname);
|
||||
}
|
||||
|
||||
// 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");
|
||||
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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
tun->ua = ua;
|
||||
tun->fd = -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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
#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);
|
||||
|
||||
return tun;
|
||||
}
|
||||
|
||||
void tun_close(struct tun_if* tun) {
|
||||
if (!tun) 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;
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
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++;
|
||||
|
||||
DEBUG_DEBUG(DEBUG_CATEGORY_TUN, "Wrote %zd bytes to TUN %s", nwritten, tun->ifname);
|
||||
|
||||
return nwritten;
|
||||
}
|
||||
|
||||
// Unregister sockets
|
||||
void utun_instance_unregister_sockets(struct UTUN_INSTANCE *instance) {
|
||||
if (!instance || !instance->ua) return;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
+50
-70
@@ -1,102 +1,82 @@
|
||||
// tun_if.h - TUN interface management for utun
|
||||
// tun_if.h - Simplified TUN interface management for utun
|
||||
#ifndef TUN_IF_H
|
||||
#define TUN_IF_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
// Forward declarations
|
||||
struct UTUN_INSTANCE;
|
||||
struct UASYNC;
|
||||
struct utun_config;
|
||||
struct ll_queue;
|
||||
struct memory_pool;
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define MAX_PACKET_SIZE 1500
|
||||
#define TUN_MTU_DEFAULT 1500
|
||||
#define TUN_MAX_PACKET_SIZE 1500
|
||||
|
||||
// TUN interface configuration
|
||||
struct tun_config {
|
||||
char ifname[16]; // Interface name (e.g., "tun12")
|
||||
char ip_addr[64]; // IP address with mask (e.g., "10.0.0.1/24")
|
||||
int mtu; // MTU size
|
||||
int fd; // File descriptor
|
||||
uint8_t is_up; // 1 if interface is up
|
||||
// TUN interface handle - opaque structure
|
||||
struct tun_if {
|
||||
char ifname[16]; // Interface name (e.g., "tun12")
|
||||
int fd; // File descriptor
|
||||
struct UASYNC* ua; // uasync instance
|
||||
void* socket_id; // Socket ID from uasync_add_socket
|
||||
struct memory_pool* pool; // Pool for ETCP_FRAGMENT structures
|
||||
struct ll_queue* input_queue; // Queue for incoming packets (ETCP_FRAGMENT)
|
||||
// Statistics
|
||||
uint64_t bytes_read; // Bytes read from TUN
|
||||
uint64_t bytes_written; // Bytes written to TUN
|
||||
uint32_t packets_read; // Packets read from TUN
|
||||
uint32_t packets_written; // Packets written to TUN
|
||||
uint32_t read_errors; // Read errors
|
||||
uint32_t write_errors; // Write errors
|
||||
uint64_t bytes_read; // Bytes read from TUN
|
||||
uint64_t bytes_written; // Bytes written to TUN
|
||||
uint32_t packets_read; // Packets read from TUN
|
||||
uint32_t packets_written; // Packets written to TUN
|
||||
uint32_t read_errors; // Read errors
|
||||
uint32_t write_errors; // Write errors
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Create and configure TUN interface
|
||||
* @param config TUN configuration (ifname can be empty for auto)
|
||||
* @return 0 on success, -1 on error
|
||||
* @brief Initialize TUN interface
|
||||
* Creates TUN device, sets MTU=1500, brings interface up,
|
||||
* configures IP from config, registers read callback in uasync,
|
||||
* creates memory pool and input queue for incoming packets.
|
||||
* @param ua uasync instance for event handling
|
||||
* @param config Configuration containing tun_ip and other settings
|
||||
* @return Pointer to tun_if on success, NULL on error
|
||||
*/
|
||||
int tun_create(struct tun_config *config);
|
||||
struct tun_if* tun_init(struct UASYNC* ua, struct utun_config* config);
|
||||
|
||||
/**
|
||||
* @brief Configure IP address on TUN interface
|
||||
* @param ifname Interface name
|
||||
* @param ip_addr IP address with mask (e.g., "10.0.0.1/24")
|
||||
* @return 0 on success, -1 on error
|
||||
* @brief Close TUN interface and free resources
|
||||
* Unregisters socket from uasync, closes fd, drains and frees
|
||||
* all packets from input_queue, destroys pool and queue.
|
||||
* @param tun TUN interface handle
|
||||
*/
|
||||
int tun_set_ip(const char *ifname, const char *ip_addr);
|
||||
|
||||
/**
|
||||
* @brief Bring TUN interface up
|
||||
* @param ifname Interface name
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int tun_set_up(const char *ifname);
|
||||
|
||||
/**
|
||||
* @brief Set MTU on TUN interface
|
||||
* @param ifname Interface name
|
||||
* @param mtu MTU value
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int tun_set_mtu(const char *ifname, int mtu);
|
||||
|
||||
/**
|
||||
* @brief Read packet from TUN interface
|
||||
* @param fd TUN file descriptor
|
||||
* @param buffer Buffer to store packet
|
||||
* @param size Buffer size
|
||||
* @return Number of bytes read, -1 on error
|
||||
*/
|
||||
ssize_t tun_read(int fd, uint8_t *buffer, size_t size);
|
||||
void tun_close(struct tun_if* tun);
|
||||
|
||||
/**
|
||||
* @brief Write packet to TUN interface
|
||||
* @param fd TUN file descriptor
|
||||
* @param buffer Packet data
|
||||
* @param size Packet size
|
||||
* @param tun TUN interface handle
|
||||
* @param buf Packet data
|
||||
* @param len Packet size
|
||||
* @return Number of bytes written, -1 on error
|
||||
*/
|
||||
ssize_t tun_write(int fd, const uint8_t *buffer, size_t size);
|
||||
ssize_t tun_write(struct tun_if* tun, const uint8_t* buf, size_t len);
|
||||
|
||||
/**
|
||||
* @brief Close TUN interface
|
||||
* @param config TUN configuration
|
||||
* @brief Get input queue for reading packets
|
||||
* User should call queue_data_get(tun->input_queue) to retrieve packets.
|
||||
* Each packet is struct ETCP_FRAGMENT with:
|
||||
* - ll.dgram: malloc'd packet data (user must free)
|
||||
* - ll.len: packet length
|
||||
* User must free dgram and return fragment to pool via memory_pool_free().
|
||||
* @param tun TUN interface handle
|
||||
* @return Pointer to input queue
|
||||
*/
|
||||
void tun_close(struct tun_config *config);
|
||||
|
||||
/**
|
||||
* @brief Get current TUN configuration
|
||||
* @param ifname Interface name
|
||||
* @param config Output configuration
|
||||
* @return 0 on success, -1 on error
|
||||
*/
|
||||
int tun_get_config(const char *ifname, struct tun_config *config);
|
||||
|
||||
int utun_instance_register_sockets(struct UTUN_INSTANCE *instance);
|
||||
void utun_instance_unregister_sockets(struct UTUN_INSTANCE *instance);
|
||||
|
||||
// TUN callback function
|
||||
void tun_read_callback(int fd, void* user_arg);
|
||||
static inline struct ll_queue* tun_get_input_queue(struct tun_if* tun) {
|
||||
return tun ? tun->input_queue : NULL;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
+1
-7
@@ -292,12 +292,7 @@ int main(int argc, char *argv[]) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Register sockets with uasync
|
||||
if (utun_instance_register_sockets(instance) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_MEMORY, "Failed to register sockets");
|
||||
utun_instance_destroy(instance);
|
||||
return 1;
|
||||
}
|
||||
// Note: TUN socket is registered in tun_init(), ETCP sockets in init_connections()
|
||||
|
||||
// Setup signal handlers
|
||||
signal(SIGINT, signal_handler);
|
||||
@@ -324,7 +319,6 @@ int main(int argc, char *argv[]) {
|
||||
// Cleanup
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Shutdown");
|
||||
|
||||
utun_instance_unregister_sockets(instance);
|
||||
utun_instance_destroy(instance);
|
||||
|
||||
// Destroy uasync instance after instance is destroyed
|
||||
|
||||
+16
-84
@@ -81,70 +81,17 @@ struct UTUN_INSTANCE* utun_instance_create(struct UASYNC* ua, const char *config
|
||||
|
||||
// Initialize TUN device only if enabled
|
||||
if (g_tun_init_enabled) {
|
||||
// Initialize TUN device
|
||||
if (tun_create(&instance->tun) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to create TUN device");
|
||||
instance->tun = tun_init(ua, instance->config);
|
||||
if (!instance->tun) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to initialize TUN device");
|
||||
free(instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Configure TUN device IP (BSD: use config IP as-is, Linux/Win: IP/32)
|
||||
char tun_ip_str[64];
|
||||
char ip_buffer[64];
|
||||
|
||||
// Convert struct IP to string using inet_ntop
|
||||
if (instance->config->global.tun_ip.family == AF_INET) {
|
||||
inet_ntop(AF_INET, &instance->config->global.tun_ip.addr.v4, ip_buffer, sizeof(ip_buffer));
|
||||
} else {
|
||||
inet_ntop(AF_INET6, &instance->config->global.tun_ip.addr.v6, ip_buffer, sizeof(ip_buffer));
|
||||
}
|
||||
|
||||
#ifdef __linux__
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-truncation"
|
||||
snprintf(tun_ip_str, sizeof(tun_ip_str), "%s/32", ip_buffer);
|
||||
#pragma GCC diagnostic pop
|
||||
#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__APPLE__)
|
||||
// BSD systems: use config IP as-is, peer IP will be 192.0.2.1
|
||||
snprintf(tun_ip_str, sizeof(tun_ip_str), "%s", ip_buffer);
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wformat-truncation"
|
||||
snprintf(tun_ip_str, sizeof(tun_ip_str), "%s/32", ip_buffer); // Default to /32
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
if (tun_set_ip(instance->tun.ifname, tun_ip_str) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN IP: %s", tun_ip_str);
|
||||
tun_close(&instance->tun);
|
||||
free(instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Set MTU (default 1500)
|
||||
int mtu = instance->config->global.mtu > 0 ? instance->config->global.mtu : 1500;
|
||||
if (tun_set_mtu(instance->tun.ifname, mtu) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to set TUN MTU: %d", mtu);
|
||||
tun_close(&instance->tun);
|
||||
free(instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (tun_set_up(instance->tun.ifname) < 0) {
|
||||
DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to bring up TUN interface");
|
||||
tun_close(&instance->tun);
|
||||
free(instance);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN interface initialized: %s with IP %s",
|
||||
instance->tun.ifname, tun_ip_str);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN interface initialized: %s", instance->tun->ifname);
|
||||
} else {
|
||||
// TUN initialization disabled - skip TUN setup
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN initialization disabled - skipping TUN device setup");
|
||||
// Initialize TUN structure with safe defaults
|
||||
memset(&instance->tun, 0, sizeof(instance->tun));
|
||||
instance->tun.fd = -1; // Invalid file descriptor to indicate no TUN device
|
||||
instance->tun = NULL;
|
||||
}
|
||||
|
||||
return instance;
|
||||
@@ -162,12 +109,6 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
|
||||
// Stop running if not already
|
||||
instance->running = 0;
|
||||
|
||||
// Unregister all sockets from uasync BEFORE destroying ETCP components
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Unregistering sockets from uasync");
|
||||
utun_instance_unregister_sockets(instance);
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Socket unregistration complete");
|
||||
|
||||
|
||||
// Cleanup ETCP sockets and connections FIRST (before destroying uasync)
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] Cleaning up ETCP sockets and connections");
|
||||
struct ETCP_SOCKET* sock = instance->etcp_sockets;
|
||||
@@ -194,9 +135,10 @@ void utun_instance_destroy(struct UTUN_INSTANCE *instance) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_MEMORY, "[INSTANCE_DESTROY] ETCP connections cleanup complete");
|
||||
|
||||
// Cleanup TUN
|
||||
if (instance->tun.fd >= 0) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Closing TUN interface: %s", instance->tun.ifname);
|
||||
tun_close(&instance->tun);
|
||||
if (instance->tun) {
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "Closing TUN interface: %s", instance->tun->ifname);
|
||||
tun_close(instance->tun);
|
||||
instance->tun = NULL;
|
||||
}
|
||||
|
||||
// Cleanup config
|
||||
@@ -258,17 +200,7 @@ void utun_instance_stop(struct UTUN_INSTANCE *instance) {
|
||||
int utun_instance_init(struct UTUN_INSTANCE *instance) {
|
||||
if (!instance) return -1;
|
||||
|
||||
// Register TUN socket with uasync
|
||||
if (instance->tun.fd >= 0) {
|
||||
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 with uasync");
|
||||
return -1;
|
||||
}
|
||||
DEBUG_INFO(DEBUG_CATEGORY_TUN, "TUN interface registered: %s (fd=%d)",
|
||||
instance->tun.ifname, instance->tun.fd);
|
||||
}
|
||||
// Note: TUN socket is already registered in tun_init()
|
||||
|
||||
// Initialize connections
|
||||
// Добавляем прямой вывод для отладки проблемы double free
|
||||
@@ -344,8 +276,8 @@ void utun_instance_diagnose_leaks(struct UTUN_INSTANCE *instance, const char *ph
|
||||
|
||||
printf("\n🔧 RESOURCE STATUS:\n");
|
||||
printf(" Memory Pool: %s\n", instance->pkt_pool ? "ALLOCATED" : "NULL");
|
||||
printf(" TUN Socket ID: %p\n", instance->tun_socket_id);
|
||||
printf(" TUN FD: %d\n", instance->tun.fd);
|
||||
printf(" TUN Interface: %s\n", instance->tun ? instance->tun->ifname : "NULL");
|
||||
printf(" TUN FD: %d\n", instance->tun ? instance->tun->fd : -1);
|
||||
printf(" Connections list: %p\n", instance->connections);
|
||||
printf(" ETCP Sockets list: %p\n", instance->etcp_sockets);
|
||||
|
||||
@@ -353,8 +285,8 @@ void utun_instance_diagnose_leaks(struct UTUN_INSTANCE *instance, const char *ph
|
||||
if (instance->pkt_pool) {
|
||||
printf(" ❌ Memory Pool not freed\n");
|
||||
}
|
||||
if (instance->tun_socket_id) {
|
||||
printf(" ❌ TUN socket not unregistered from uasync\n");
|
||||
if (instance->tun) {
|
||||
printf(" ❌ TUN interface not closed\n");
|
||||
}
|
||||
if (report.etcp_sockets_count > 0) {
|
||||
printf(" ❌ %d ETCP sockets still allocated\n", report.etcp_sockets_count);
|
||||
@@ -370,8 +302,8 @@ void utun_instance_diagnose_leaks(struct UTUN_INSTANCE *instance, const char *ph
|
||||
if (instance->pkt_pool) {
|
||||
printf(" → Call memory_pool_destroy() before freeing instance\n");
|
||||
}
|
||||
if (instance->tun_socket_id) {
|
||||
printf(" → Call uasync_remove_socket() for TUN socket\n");
|
||||
if (instance->tun) {
|
||||
printf(" → Call tun_close() to close TUN interface\n");
|
||||
}
|
||||
if (report.etcp_sockets_count > 0) {
|
||||
printf(" → Iterate and call etcp_socket_remove() for each socket\n");
|
||||
|
||||
+2
-3
@@ -6,7 +6,6 @@
|
||||
#include <stdio.h>
|
||||
#include "../lib/memory_pool.h"
|
||||
#include "secure_channel.h"
|
||||
#include "tun_if.h"
|
||||
|
||||
// Forward declarations
|
||||
struct utun_config;
|
||||
@@ -14,6 +13,7 @@ struct uasync_s;
|
||||
struct routing_table;
|
||||
struct ETCP_CONN;
|
||||
struct ETCP_SOCKET;
|
||||
struct tun_if;
|
||||
|
||||
// uTun instance configuration
|
||||
struct UTUN_INSTANCE {
|
||||
@@ -21,8 +21,7 @@ struct UTUN_INSTANCE {
|
||||
struct utun_config *config;
|
||||
|
||||
// TUN interface
|
||||
struct tun_config tun;
|
||||
void *tun_socket_id; // Socket ID from uasync_add_socket
|
||||
struct tun_if* tun;
|
||||
|
||||
// Identification
|
||||
uint64_t node_id;
|
||||
|
||||
Reference in new issue
Block a user