From e6308f6e28fe40312d9a99b8c3ce97a37c496b70 Mon Sep 17 00:00:00 2001 From: PancakeTAS Date: Sat, 13 Jun 2026 22:33:14 +0200 Subject: feat: Implement TUN module --- CMakeLists.txt | 1 + src/tun.c | 104 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/tun.h | 14 ++++++++ 3 files changed, 119 insertions(+) create mode 100644 src/tun.c create mode 100644 src/tun.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 0820f7e..ad8e726 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable(mpu "src/heap.c" "src/mpu.c" "src/p2p.c" + "src/tun.c" "src/main.c") set_target_properties(mpu PROPERTIES diff --git a/src/tun.c b/src/tun.c new file mode 100644 index 0000000..8658893 --- /dev/null +++ b/src/tun.c @@ -0,0 +1,104 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#include "tun.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int parse_cidr(const char* cidr, struct in_addr* addr, struct in_addr* netmask) { + char ip[INET_ADDRSTRLEN]; + int prefix = 0; + + if (sscanf(cidr, "%[^/]/%d", ip, &prefix) != 2 || prefix < 0 || prefix > 32) { + return -1; + } + + *netmask = (struct in_addr) { + .s_addr = htonl(0xFFFFFFFF << (32 - prefix)), + }; + if (!inet_aton(ip, addr)) { + return -1; + } + + return 0; +} + +int tun_alloc(const char* ifname, const char* cidr, int mtu) { + struct in_addr addr, netmask; + if (parse_cidr(cidr, &addr, &netmask) < 0) { + errno = EINVAL; + goto err; + } + + struct ifreq ifr = {0}; + strncpy(ifr.ifr_name, ifname, IFNAMSIZ); + + // Create the tun device + int fd = open("/dev/net/tun", O_RDWR); + if (fd < 0) { + goto err; + } + + ifr.ifr_flags = (short) (IFF_TUN | IFF_NO_PI | IFF_TUN_EXCL); + if (ioctl(fd, TUNSETIFF, &ifr) < 0) { + goto err_close_fd; + } + + // Configure IP address, netmask and MTU + int sockfd = socket(AF_INET, SOCK_DGRAM, 0); + if (sockfd < 0) { + goto err_close_fd; + } + + struct sockaddr_in* sin = (struct sockaddr_in*) &ifr.ifr_data; + + *sin = (struct sockaddr_in) { + .sin_family = AF_INET, + .sin_addr = addr, + }; + if (ioctl(sockfd, SIOCSIFADDR, &ifr) < 0) { + goto err_close_sockfd; + } + + *sin = (struct sockaddr_in) { + .sin_family = AF_INET, + .sin_addr = netmask, + }; + if (ioctl(sockfd, SIOCSIFNETMASK, &ifr) < 0) { + goto err_close_sockfd; + } + + ifr.ifr_mtu = mtu; + if (ioctl(sockfd, SIOCSIFMTU, &ifr) < 0) { + goto err_close_sockfd; + } + + // Bring interface up + ifr.ifr_flags = 0; + if (ioctl(sockfd, SIOCGIFFLAGS, &ifr) < 0) { + goto err_close_sockfd; + } + + ifr.ifr_flags |= IFF_UP | IFF_RUNNING; + if (ioctl(sockfd, SIOCSIFFLAGS, &ifr) < 0) { + goto err_close_sockfd; + } + + return fd; +err_close_sockfd: + close(sockfd); +err_close_fd: + close(fd); +err: + return -1; +} diff --git a/src/tun.h b/src/tun.h new file mode 100644 index 0000000..98a307d --- /dev/null +++ b/src/tun.h @@ -0,0 +1,14 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ + +#pragma once + +// +// This module implements a Linux tun device. The tun_alloc() functions creates a tun device +// with a given name, IP address, subnet mask and MTU. +// + +#include + +/// Allocate a tun device with the given CIDR (e.g. "172.16.0.1/24") and MTU. +/// Returns fd on success, -1 on failure (errno is set). +int tun_alloc(const char* ifname, const char* cidr, int mtu); -- cgit v1.3.1