// tun_if.c - TUN interface management implementation #define _POSIX_C_SOURCE 200809L #include "tun_if.h" #include "../lib/debug_config.h" #include "routing.h" #include "../lib/u_async.h" #include "etcp_connections.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Create TUN device static int create_tun_device(char *ifname, size_t ifname_len) { struct ifreq ifr; int fd; fd = open("/dev/net/tun", O_RDWR); if (fd < 0) { DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to open /dev/net/tun: %s", strerror(errno)); return -1; } memset(&ifr, 0, sizeof(ifr)); ifr.ifr_flags = IFF_TUN | IFF_NO_PI; if (ifname && ifname_len > 0 && ifname[0] != '\0') { strncpy(ifr.ifr_name, ifname, IFNAMSIZ - 1); } if (ioctl(fd, TUNSETIFF, &ifr) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Failed to configure TUN device: %s", strerror(errno)); close(fd); return -1; } if (ifname && ifname_len > 0) { strncpy(ifname, ifr.ifr_name, ifname_len - 1); ifname[ifname_len - 1] = '\0'; } return fd; } // Run system command static int run_command(const char *cmd) { int ret = system(cmd); if (ret == -1) { perror("system"); return -1; } if (WIFEXITED(ret) && WEXITSTATUS(ret) != 0) { DEBUG_ERROR(DEBUG_CATEGORY_TUN, "Command failed: %s", cmd); return -1; } return 0; } // Parse IP address and mask static int parse_ip_mask(const char *ip_addr, char *ip, size_t ip_len, int *mask) { if (!ip_addr || !ip || !mask) return -1; char *slash = strchr(ip_addr, '/'); if (!slash) { // Default mask /32 *mask = 32; strncpy(ip, ip_addr, ip_len - 1); ip[ip_len - 1] = '\0'; } else { size_t ip_size = slash - ip_addr; if (ip_size >= ip_len) return -1; strncpy(ip, ip_addr, ip_size); ip[ip_size] = '\0'; char *endptr; long mask_val = strtol(slash + 1, &endptr, 10); if (*endptr != '\0' || mask_val < 0 || mask_val > 32) return -1; *mask = (int)mask_val; } return 0; } 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) { if (!ifname || !ip_addr) { errno = EINVAL; return -1; } char ip[64]; int mask; if (parse_ip_mask(ip_addr, ip, sizeof(ip), &mask) < 0) { DEBUG_ERROR(DEBUG_CATEGORY_CONFIG, "Invalid IP address format: %s", ip_addr); errno = EINVAL; return -1; } char cmd[256]; snprintf(cmd, sizeof(cmd), "ip addr add %s dev %s", ip_addr, ifname); if (run_command(cmd) < 0) { return -1; } return 0; } int tun_set_up(const char *ifname) { if (!ifname) { errno = EINVAL; return -1; } char cmd[256]; snprintf(cmd, sizeof(cmd), "ip link set %s up", ifname); if (run_command(cmd) < 0) { return -1; } return 0; } int tun_set_mtu(const char *ifname, int mtu) { if (!ifname || mtu <= 0) { errno = EINVAL; return -1; } char cmd[256]; snprintf(cmd, sizeof(cmd), "ip link set %s mtu %d", ifname, mtu); if (run_command(cmd) < 0) { return -1; } 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 parsing ip addr show output 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 tun_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; } // 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]; // 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; } if (nread > 0) { // Route packet based on destination IP uint32_t dest_ip = get_dest_ip(buffer, nread); struct route_entry route; if (routing_table_lookup(instance->routing_table, dest_ip, &route)) { // Found route, send to next hop connection if (route.next_hop) { struct sockaddr_in dest_addr; memset(&dest_addr, 0, sizeof(dest_addr)); dest_addr.sin_family = AF_INET; dest_addr.sin_addr.s_addr = route.next_hop_ip; // todo: отправлять в модуль роутинга все входящие пакеты. когда этот модуль будет. модуль роутинга это не роутинг таблица (routing.h) // if (etcp_connections_send(route.next_hop, buffer, nread, (struct sockaddr*)&dest_addr, sizeof(dest_addr)) < 0) { // DEBUG_ERROR(DEBUG_CATEGORY_ETCP, "Failed to send packet via route"); // } } else { // Local route - no forwarding needed DEBUG_DEBUG(DEBUG_CATEGORY_ROUTING, "Local packet, no forwarding"); } } else { // No route found, drop packet char ip_str[16]; ip_to_string(dest_ip, ip_str); DEBUG_ERROR(DEBUG_CATEGORY_ROUTING, "No route for destination IP %s", ip_str); } } } // 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"); 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"); return -1; } DEBUG_INFO(DEBUG_CATEGORY_TUN, "Registered TUN socket (fd=%d)", instance->tun.fd); return 0; } // 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); } }