diff options
| author | PancakeTAS <pancake@mgnet.work> | 2026-06-13 22:33:14 +0200 |
|---|---|---|
| committer | PancakeTAS <pancake@mgnet.work> | 2026-06-14 16:27:32 +0200 |
| commit | e6308f6e28fe40312d9a99b8c3ce97a37c496b70 (patch) | |
| tree | 3724b13fd8a0cab38a9f63d9aca8397d37d6fa5d | |
| parent | perf(mpu): Remove zero-copy items (diff) | |
feat: Implement TUN modulemaster
| -rw-r--r-- | CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/tun.c | 104 | ||||
| -rw-r--r-- | src/tun.h | 14 |
3 files changed, 119 insertions, 0 deletions
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 <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <linux/if.h> +#include <linux/if_tun.h> +#include <linux/sockios.h> +#include <netinet/in.h> +#include <stdio.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <unistd.h> + +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 <linux/if.h> + +/// 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); |
