138 lines
3.4 KiB
C
138 lines
3.4 KiB
C
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <linux/if.h>
|
|
#include <linux/if_tun.h>
|
|
#include <signal.h>
|
|
#include <stdbool.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/ioctl.h>
|
|
#include <unistd.h>
|
|
|
|
#define DEVICE_NODE_TUN "/dev/net/tun"
|
|
#define BUFFER_SIZE 0x1000
|
|
|
|
#define EXIT_SUCCESS 0
|
|
#define EXIT_USAGE 1
|
|
#define EXIT_RUNTIME 2
|
|
|
|
int file_descriptor;
|
|
char buffer[BUFFER_SIZE];
|
|
struct ifreq ifr;
|
|
bool stop_now = false;
|
|
ssize_t read_size;
|
|
ssize_t write_size;
|
|
bool just_created_dup;
|
|
int stdin_dup;
|
|
|
|
void stop() {
|
|
stop_now = true;
|
|
}
|
|
|
|
void yeet(int fd) {
|
|
if (fcntl(fd, F_GETFD) != -1) {
|
|
close(fd);
|
|
}
|
|
}
|
|
|
|
void recreate_dup() {
|
|
just_created_dup = true;
|
|
yeet(stdin_dup);
|
|
stdin_dup = dup(fileno(stdin));
|
|
}
|
|
|
|
int main(int argc, char** argv) {
|
|
if (argc != 2) {
|
|
fprintf(stderr, "Usage: %s TAP\n", argv[0]);
|
|
return EXIT_USAGE;
|
|
} else if ((strlen(argv[1])==2 && strncmp(argv[1], "-h", 2)==0) || (strlen(argv[1])==6 &&strncmp(argv[1], "--help", 6))) {
|
|
fprintf(stdout, "Usage: %s TAP\n", argv[0]);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
if (freopen(NULL, "rb", stdin) == NULL) {
|
|
fprintf(stderr, "Failed to set stdin to binary mode: %i\n", errno);
|
|
return EXIT_RUNTIME;
|
|
}
|
|
|
|
stdin_dup = dup(fileno(stdin));
|
|
if (stdin_dup == -1) {
|
|
fprintf(stderr, "Failed to dup() stdin: %i\n", errno);
|
|
}
|
|
|
|
if (freopen(NULL, "wb", stdout) == NULL) {
|
|
fprintf(stderr, "Failed to set stdout to binary mode: %i\n", errno);
|
|
return EXIT_RUNTIME;
|
|
}
|
|
|
|
file_descriptor = open(DEVICE_NODE_TUN, O_RDWR | O_NONBLOCK);
|
|
if (file_descriptor == -1) {
|
|
fprintf(stderr, "Failed to open %s: %i\n", DEVICE_NODE_TUN, errno);
|
|
return EXIT_RUNTIME;
|
|
}
|
|
|
|
memset(&ifr, 0, sizeof(ifr));
|
|
ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
|
|
strncpy(ifr.ifr_name, argv[1], IFNAMSIZ);
|
|
|
|
if (ioctl(file_descriptor, TUNSETIFF, &ifr) == -1) {
|
|
fprintf(stderr, "An error occurred while trying to ioctl: %i\n", errno);
|
|
close(file_descriptor);
|
|
return EXIT_RUNTIME;
|
|
}
|
|
|
|
signal(SIGINT, stop);
|
|
signal(SIGTERM, stop);
|
|
signal(SIGALRM, recreate_dup);
|
|
|
|
ualarm(500000, 500000);
|
|
|
|
while (fcntl(file_descriptor, F_GETFD) != -1 && !stop_now) {
|
|
read_size = read(file_descriptor, buffer, BUFFER_SIZE);
|
|
if (read_size == -1) {
|
|
fprintf(stderr, "Failed to read from tap: %i\n", errno);
|
|
yeet(file_descriptor);
|
|
return EXIT_RUNTIME;
|
|
}
|
|
for (
|
|
write_size = 0;
|
|
read_size > 0 && !stop_now;
|
|
read_size = read_size - write_size
|
|
) {
|
|
// using read_size as the amount of remaining bytes
|
|
write_size = write(fileno(stdout), buffer, read_size);
|
|
if (write_size == -1) {
|
|
fprintf(stderr, "Failed to write stdout: %i\n", errno);
|
|
yeet(file_descriptor);
|
|
return EXIT_RUNTIME;
|
|
}
|
|
}
|
|
just_created_dup = false;
|
|
read_size = read(stdin_dup, buffer, BUFFER_SIZE);
|
|
if (read_size == -1) {
|
|
fprintf(stderr, "Failed to read from stdin: %i\n", errno);
|
|
yeet(file_descriptor);
|
|
return EXIT_RUNTIME;
|
|
}
|
|
if (read_size == 0 && !just_created_dup) {
|
|
// probably EOF
|
|
break;
|
|
}
|
|
for (
|
|
write_size = 0;
|
|
read_size > 0 && !stop_now;
|
|
read_size = read_size - write_size
|
|
) {
|
|
write_size = write(file_descriptor, buffer, read_size);
|
|
if (write_size == -1) {
|
|
fprintf(stderr, "Failed to write stdout: %i\n", errno);
|
|
yeet(file_descriptor);
|
|
return EXIT_RUNTIME;
|
|
}
|
|
}
|
|
}
|
|
|
|
yeet(file_descriptor);
|
|
return EXIT_SUCCESS;
|
|
}
|