You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

190 lines
6.8 KiB

#include "test_virtual_tun.h"
#include "../lib/debug_config.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#ifndef DEBUG_CATEGORY_TEST
#define DEBUG_CATEGORY_TEST (1 << 30)
#endif
// Create virtual TUN with bidirectional pipes
struct virtual_tun* virtual_tun_create(const char* ifname) {
if (!ifname) {
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "NULL interface name provided");
return NULL;
}
struct virtual_tun* vtun = calloc(1, sizeof(struct virtual_tun));
if (!vtun) {
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to allocate virtual TUN");
return NULL;
}
// Copy interface name
strncpy(vtun->ifname, ifname, sizeof(vtun->ifname) - 1);
vtun->ifname[sizeof(vtun->ifname) - 1] = '\0';
vtun->enabled = true;
// Create pipes for bidirectional communication
// read_pipe: [0] = read end, [1] = write end (for packets from network)
// write_pipe: [0] = read end, [1] = write end (for packets to network)
if (pipe(vtun->read_pipe) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to create read pipe: %s", strerror(errno));
free(vtun);
return NULL;
}
if (pipe(vtun->write_pipe) < 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to create write pipe: %s", strerror(errno));
close(vtun->read_pipe[0]);
close(vtun->read_pipe[1]);
free(vtun);
return NULL;
}
// Set non-blocking mode on pipe ends
for (int i = 0; i < 2; i++) {
int flags = fcntl(vtun->read_pipe[i], F_GETFL, 0);
if (flags == -1 || fcntl(vtun->read_pipe[i], F_SETFL, flags | O_NONBLOCK) < 0) {
DEBUG_WARN(DEBUG_CATEGORY_TEST, "Failed to set non-blocking on read pipe[%d]: %s", i, strerror(errno));
}
flags = fcntl(vtun->write_pipe[i], F_GETFL, 0);
if (flags == -1 || fcntl(vtun->write_pipe[i], F_SETFL, flags | O_NONBLOCK) < 0) {
DEBUG_WARN(DEBUG_CATEGORY_TEST, "Failed to set non-blocking on write pipe[%d]: %s", i, strerror(errno));
}
}
DEBUG_INFO(DEBUG_CATEGORY_TEST, "Virtual TUN created: %s (read_fd=%d, write_fd=%d)",
vtun->ifname, vtun->read_pipe[0], vtun->write_pipe[1]);
return vtun;
}
// Cleanup virtual TUN
void virtual_tun_destroy(struct virtual_tun* vtun) {
if (!vtun) return;
DEBUG_INFO(DEBUG_CATEGORY_TEST, "Destroying virtual TUN: %s (stats: sent=%zu packets/%zu bytes, recv=%zu packets/%zu bytes)",
vtun->ifname, vtun->stats.packets_sent, vtun->stats.bytes_sent,
vtun->stats.packets_received, vtun->stats.bytes_received);
// Close all pipe file descriptors
if (vtun->read_pipe[0] >= 0) close(vtun->read_pipe[0]);
if (vtun->read_pipe[1] >= 0) close(vtun->read_pipe[1]);
if (vtun->write_pipe[0] >= 0) close(vtun->write_pipe[0]);
if (vtun->write_pipe[1] >= 0) close(vtun->write_pipe[1]);
free(vtun);
}
// Get file descriptor for reading (simulates TUN device read)
int virtual_tun_get_read_fd(struct virtual_tun* vtun) {
if (!vtun || !vtun->enabled) return -1;
return vtun->read_pipe[0]; // Read end of read pipe
}
// Get file descriptor for writing (simulates TUN device write)
int virtual_tun_get_write_fd(struct virtual_tun* vtun) {
if (!vtun || !vtun->enabled) return -1;
return vtun->write_pipe[1]; // Write end of write pipe
}
// Inject packet into virtual TUN (simulates packet from network)
int virtual_tun_inject_packet(struct virtual_tun* vtun, const uint8_t* packet, size_t len) {
if (!vtun || !vtun->enabled || !packet || len == 0) {
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Invalid parameters for packet injection");
return -1;
}
if (len > VIRTUAL_TUN_MAX_PACKET_SIZE) {
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Packet too large: %zu > %d", len, VIRTUAL_TUN_MAX_PACKET_SIZE);
return -1;
}
// Write packet to read pipe (simulates packet arriving from network)
ssize_t written = write(vtun->read_pipe[1], packet, len);
if (written < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to inject packet: %s", strerror(errno));
}
return -1;
}
vtun->stats.packets_received++;
vtun->stats.bytes_received += written;
DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "Injected packet into %s: %zu bytes", vtun->ifname, written);
return 0;
}
// Read packet from virtual TUN (captures packets going to network)
ssize_t virtual_tun_read_packet(struct virtual_tun* vtun, uint8_t* buffer, size_t max_len) {
if (!vtun || !vtun->enabled || !buffer || max_len == 0) {
return -1;
}
// Read from write pipe (captures packets going to network)
ssize_t bytes_read = read(vtun->write_pipe[0], buffer, max_len);
if (bytes_read < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to read packet: %s", strerror(errno));
}
return -1;
}
if (bytes_read > 0) {
vtun->stats.packets_sent++;
vtun->stats.bytes_sent += bytes_read;
DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "Read packet from %s: %zu bytes", vtun->ifname, bytes_read);
}
return bytes_read;
}
// Write packet to virtual TUN (sends packet to network)
ssize_t virtual_tun_write_packet(struct virtual_tun* vtun, const uint8_t* packet, size_t len) {
if (!vtun || !vtun->enabled || !packet || len == 0) {
return -1;
}
if (len > VIRTUAL_TUN_MAX_PACKET_SIZE) {
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Packet too large: %zu > %d", len, VIRTUAL_TUN_MAX_PACKET_SIZE);
return -1;
}
// Write packet to write pipe (sends to network)
ssize_t written = write(vtun->write_pipe[1], packet, len);
if (written < 0) {
if (errno != EAGAIN && errno != EWOULDBLOCK) {
DEBUG_ERROR(DEBUG_CATEGORY_TEST, "Failed to write packet: %s", strerror(errno));
}
return -1;
}
DEBUG_DEBUG(DEBUG_CATEGORY_TEST, "Wrote packet to %s: %zu bytes", vtun->ifname, written);
return written;
}
// Get virtual TUN statistics
void virtual_tun_get_stats(struct virtual_tun* vtun, size_t* packets_sent, size_t* packets_received,
size_t* bytes_sent, size_t* bytes_received) {
if (!vtun) return;
if (packets_sent) *packets_sent = vtun->stats.packets_sent;
if (packets_received) *packets_received = vtun->stats.packets_received;
if (bytes_sent) *bytes_sent = vtun->stats.bytes_sent;
if (bytes_received) *bytes_received = vtun->stats.bytes_received;
}
// Reset virtual TUN statistics
void virtual_tun_reset_stats(struct virtual_tun* vtun) {
if (!vtun) return;
memset(&vtun->stats, 0, sizeof(vtun->stats));
DEBUG_INFO(DEBUG_CATEGORY_TEST, "Reset statistics for virtual TUN: %s", vtun->ifname);
}