Milan Stephan
Fotografie & IT

Zurück zur SP2 Übersicht

snailproxy.c

/* * * * * * * * * * * * * * * *
 *  nudelsalat's snail proxy   *
 *    milan.stephan@fau.de     *
 * https://sp.milanstephan.de  *
 * * * * * * * * * * * * * * * */
/*

Version: WS 2021 / 10.10.2021

Ich hab das heute Nacht schnell zusammengehackt und man könnte Sachen definitiv schöner und robuster lösen, fehlerbehandeln und Ressourcen freigeben. ;)
-> Nicht als Vorlage für was auch immer nehmen, besonders nicht in SP. :D

Wichtig:
- Funktioniert nur im Cip-Netz (das Script braucht Zugriff auf den Mailserver faui03.cs.fau.de)
- snail und der Proxy müssen auf dem selben Rechner laufen

Anleitung:
- Code in eine neue Datei snailproxy.c kopieren (muss nicht im gleichen Verzeichnis wie die snail liegen)
- Im Cip bauen: gcc -std=c11 -D_XOPEN_SOURCE=700 -Werror -Wall -o snailproxy snailproxy.c
- Snail-Proxy starten: ./snailproxy

- In eurer snail.c bei getaddrinfo statt "faui03.cs.fau.de" "localhost" eintragen und statt "25" "1125" eintragen.
- Eure snail wie gewohnt testen => Der Proxy zeigt jetzt den Traffic zwischen der snail und dem Mailserver an.
- Vor der Abgabe wieder "faui03.cs.fau.de" und "25" eintragen. ;)

*/

#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <stdio.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <netdb.h>
#include <signal.h>

static void die(const char *msg) {
	perror(msg);
	exit(EXIT_FAILURE);
}

#define IN  0
#define OUT 1

static void copy(FILE *src, FILE *dst, int direction, pid_t partner) {

	char *col  = (direction == OUT) ? "\e[0;32m" : "\e[0;31m";
	char *hcol = (direction == OUT) ? "\e[1;32m" : "\e[1;31m";
	char *dir  = (direction == OUT) ? "> " : "< ";

	int last = '\n';
	while (1) {

		int c = fgetc(src);
		if (c == EOF) {
			printf("\n%s<lost connection>\e[0m\n\n", hcol);
			fflush(stdout);
			if (partner) {
				kill(partner, 9);
			}
			break;
		}
		fputc(c, dst);
		fflush(dst);


		if (last == '\n') {
			printf("%s%s\e[0m", hcol, dir);
			fflush(stdout);
		}

		if (c == '\r') {
			printf("%s\\r\e[0m", hcol);
			fflush(stdout);
		}
		if (c == '\n') {
			printf("%s\\n\e[0m", hcol);
			fflush(stdout);
		}

		if (c != '\r') {
			printf("%s%c\e[0m", col, c);
			fflush(stdout);
		}

		last = c;
	}
}

int main(int argc, char *argv[]) {

	struct sigaction sa = {
		.sa_handler = SIG_IGN,
		.sa_flags = SA_RESTART,
	};
	sigemptyset(&sa.sa_mask);

	sigaction(SIGCHLD, &sa, NULL);

	const int listenSock = socket(AF_INET6, SOCK_STREAM, 0);
	if (listenSock == -1) {
		die("listenSock");
	}

	const struct sockaddr_in6 name = {
		.sin6_family = AF_INET6,
		.sin6_port = htons(1125),
		.sin6_addr = in6addr_loopback,
	};

	const int flag = 1;
	if (setsockopt(listenSock, SOL_SOCKET, SO_REUSEADDR, &flag, sizeof(flag)) == -1) {
		die("setsockopt");
	}

	if (bind(listenSock, (struct sockaddr *) &name, sizeof(name)) == -1) {
		die("bind");
	}

	if (listen(listenSock, SOMAXCONN) == -1) {
		die("listen");
	}

	printf("\x1B[1;37msnail-Proxy von nudelsalat | milan.stephan@fau.de | https://sp.milanstephan.de\x1B[0m\n");
	printf("Warte auf Verbindung der \x1B[1;37msnail\x1B[0m...\n");

	while (1) {

		int clientSock = accept(listenSock, NULL, NULL);
		if (clientSock < 0) {
			perror("accept");
			continue;
		}

		pid_t pid = fork();
		if (pid == -1) {
			die("fork");
		}
		if (pid == 0) {
			close(listenSock);

			struct addrinfo hints = {
				.ai_socktype = SOCK_STREAM,
				.ai_family = AF_UNSPEC,
				.ai_flags = AI_ADDRCONFIG,
			};

			struct addrinfo *head;
			getaddrinfo("faui03.cs.fau.de", "25", &hints, &head);

			int sock;
			struct addrinfo *curr;
			for (curr = head; curr != NULL; curr = curr->ai_next) {
				sock = socket(curr->ai_family, curr->ai_socktype, curr->ai_protocol);
				if (connect(sock, curr->ai_addr, curr->ai_addrlen) == 0) {
					break;
				}
				close(sock);
			}
			if (curr == NULL) {
				fprintf(stderr, "Proxy could not connect to faui03.cs.fau.de:25\n");
				exit(EXIT_FAILURE);
			}

			int sock2 = dup(sock);
			FILE *out_tx = fdopen(sock, "w");
			FILE *out_rx = fdopen(sock2, "r");

			int sock3 = dup(clientSock);
			FILE *in_tx = fdopen(clientSock, "w");
			FILE *in_rx = fdopen(sock3, "r");

			pid_t p = getpid();
			pid_t p2 = fork();
			if (p2 == -1) {
				die("fork");
			}
			if (p2 == 0) {
				copy(in_rx, out_tx, OUT, p);
				exit(EXIT_SUCCESS);
			}

			copy(out_rx, in_tx, IN, p2);
			exit(EXIT_SUCCESS);
		}

		close(clientSock);
	}
}