And now rewrite half of it bc the previous approach didn't actually work...

master
BodgeMaster 2025-02-06 17:30:48 +01:00
parent da8543510a
commit d5547c3035
1 changed files with 56 additions and 46 deletions

View File

@ -2,6 +2,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <linux/if.h> #include <linux/if.h>
#include <linux/if_tun.h> #include <linux/if_tun.h>
#include <poll.h>
#include <signal.h> #include <signal.h>
#include <stdbool.h> #include <stdbool.h>
#include <stdio.h> #include <stdio.h>
@ -10,20 +11,25 @@
#include <unistd.h> #include <unistd.h>
#define DEVICE_NODE_TUN "/dev/net/tun" #define DEVICE_NODE_TUN "/dev/net/tun"
// This number mus be larger than the MTU.
#define BUFFER_SIZE 0x1000 #define BUFFER_SIZE 0x1000
#define NUMBER_OF_POLLED_FILES 2
#define POLL_TIMEOUT 100
#define EXIT_SUCCESS 0 #define EXIT_SUCCESS 0
#define EXIT_USAGE 1 #define EXIT_USAGE 1
#define EXIT_RUNTIME 2 #define EXIT_RUNTIME 2
int file_descriptor; int file_descriptor;
int poll_result;
char buffer[BUFFER_SIZE]; char buffer[BUFFER_SIZE];
struct ifreq ifr; struct ifreq ifr;
bool stop_now = false; bool stop_now = false;
ssize_t read_size; ssize_t read_size;
ssize_t write_size; ssize_t write_size;
bool just_created_dup; // 0 file_descriptor
int stdin_dup; // 1 stdin
struct pollfd polls_pls[NUMBER_OF_POLLED_FILES];
void stop() { void stop() {
stop_now = true; stop_now = true;
@ -35,12 +41,6 @@ void yeet(int fd) {
} }
} }
void recreate_dup() {
just_created_dup = true;
yeet(stdin_dup);
stdin_dup = dup(fileno(stdin));
}
int main(int argc, char** argv) { int main(int argc, char** argv) {
if (argc != 2) { if (argc != 2) {
fprintf(stderr, "Usage: %s TAP\n", argv[0]); fprintf(stderr, "Usage: %s TAP\n", argv[0]);
@ -55,18 +55,15 @@ int main(int argc, char** argv) {
return EXIT_RUNTIME; return EXIT_RUNTIME;
} }
stdin_dup = dup(fileno(stdin)); polls_pls[1].fd = fileno(stdin);
if (stdin_dup == -1) { polls_pls[1].events = POLLIN;
fprintf(stderr, "Failed to dup() stdin: %s\n", strerror(errno));
return EXIT_RUNTIME;
}
if (freopen(NULL, "wb", stdout) == NULL) { if (freopen(NULL, "wb", stdout) == NULL) {
fprintf(stderr, "Failed to set stdout to binary mode: %s\n", strerror(errno)); fprintf(stderr, "Failed to set stdout to binary mode: %s\n", strerror(errno));
return EXIT_RUNTIME; return EXIT_RUNTIME;
} }
file_descriptor = open(DEVICE_NODE_TUN, O_RDWR | O_NONBLOCK); file_descriptor = open(DEVICE_NODE_TUN, O_RDWR);
if (file_descriptor == -1) { if (file_descriptor == -1) {
fprintf(stderr, "Failed to open %s: %s\n", DEVICE_NODE_TUN, strerror(errno)); fprintf(stderr, "Failed to open %s: %s\n", DEVICE_NODE_TUN, strerror(errno));
return EXIT_RUNTIME; return EXIT_RUNTIME;
@ -82,51 +79,64 @@ int main(int argc, char** argv) {
return EXIT_RUNTIME; return EXIT_RUNTIME;
} }
polls_pls[0].fd = file_descriptor;
polls_pls[0].events = POLLIN;
signal(SIGINT, stop); signal(SIGINT, stop);
signal(SIGTERM, stop); signal(SIGTERM, stop);
signal(SIGALRM, recreate_dup);
ualarm(500000, 500000);
while (fcntl(file_descriptor, F_GETFD) != -1 && !stop_now) { while (fcntl(file_descriptor, F_GETFD) != -1 && !stop_now) {
read_size = read(file_descriptor, buffer, BUFFER_SIZE); poll_result = poll(polls_pls, NUMBER_OF_POLLED_FILES, POLL_TIMEOUT);
if (read_size == -1) { if (poll_result == -1 && errno != EINTR) {
fprintf(stderr, "Failed to read from tap: %s\n", strerror(errno)); fprintf(stderr, "An error occurred while polling: %s\n", strerror(errno));
yeet(file_descriptor); yeet(file_descriptor);
return EXIT_RUNTIME; return EXIT_RUNTIME;
} }
for ( if (poll_result == 0) {
write_size = 0; continue;
read_size > 0 && !stop_now; }
read_size = read_size - write_size
) { if (polls_pls[0].revents & POLLIN) {
// using read_size as the amount of remaining bytes read_size = read(file_descriptor, buffer, BUFFER_SIZE);
write_size = write(fileno(stdout), buffer, read_size); if (read_size == -1) {
if (write_size == -1) { fprintf(stderr, "Failed to read from tap: %s\n", strerror(errno));
fprintf(stderr, "Failed to write stdout: %s\n", strerror(errno));
yeet(file_descriptor); yeet(file_descriptor);
return EXIT_RUNTIME; 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: %s\n", strerror(errno));
yeet(file_descriptor);
return EXIT_RUNTIME;
}
}
} }
just_created_dup = false;
read_size = read(stdin_dup, buffer, BUFFER_SIZE); if (polls_pls[1].revents & POLLIN) {
if (read_size == -1) { read_size = read(fileno(stdin), buffer, BUFFER_SIZE);
fprintf(stderr, "Failed to read from stdin: %s\n", strerror(errno)); if (read_size == -1) {
yeet(file_descriptor); fprintf(stderr, "Failed to read from stdin: %s\n", strerror(errno));
return EXIT_RUNTIME; yeet(file_descriptor);
} return EXIT_RUNTIME;
if (read_size == 0 && !just_created_dup) { }
// probably EOF if (read_size == 0) {
break; //TODO: is this still how to check for eof with poll?
} // or is there another way?
for ( break;
write_size = 0; }
read_size > 0 && !stop_now;
read_size = read_size - write_size //TODO: How to properly deal with partial reads?
) {
// accepts exactly one complete packet (Ethernet Frame?) at a time
write_size = write(file_descriptor, buffer, read_size); write_size = write(file_descriptor, buffer, read_size);
if (write_size == -1) { if (write_size == -1) {
fprintf(stderr, "Failed to write stdout: %s\n", strerror(errno)); fprintf(stderr, "Failed to write tap: %s\n", strerror(errno));
yeet(file_descriptor); yeet(file_descriptor);
return EXIT_RUNTIME; return EXIT_RUNTIME;
} }