mitmd

[archived] mitm TCP connections
git clone https://hhvn.uk/mitmd
git clone git://hhvn.uk/mitmd
Log | Files | Refs | README

mitmd.c (4179B)


      1 /* Copyright (c) 2021 hhvn <dev@hhvn.uk> */
      2 
      3 #include <stdio.h>
      4 #include <netdb.h>
      5 #include <string.h>
      6 #include <stdlib.h>
      7 #include <stdarg.h>
      8 #include <signal.h>
      9 #include <libgen.h>
     10 #include <unistd.h>
     11 #include <limits.h>
     12 #include <errno.h>
     13 #include <sys/socket.h>
     14 #include <sys/types.h>
     15 #include <sys/wait.h>
     16 #include "arg.h"
     17 
     18 #ifndef	NL_TEXTMAX
     19 #define NL_TEXTMAX 2048
     20 #endif /* NL_TEXTMAX */
     21 
     22 #define CQUEUE		255
     23 #define CLIENT_STYLE	"\033[96m>\033[0m"
     24 #define REMOTE_STYLE	"\033[90m<\033[0m"
     25 
     26 int parent = 1;
     27 char *argv0;
     28 char *myhost = "localhost",
     29      *myport = "9999",
     30      *host,
     31      *port;
     32 
     33 void
     34 die(const int exitc, const char *format, ...) {
     35 	va_list ap;
     36 
     37 	va_start(ap, format);
     38 	if (parent)
     39 		fprintf(stderr, "(Parent) fatal: ");
     40 	else
     41 		fprintf(stderr, "(Child): ");
     42 	vfprintf(stderr, format, ap);
     43 	va_end(ap);
     44 
     45 	exit(exitc);
     46 }
     47 
     48 void
     49 sighandler(int signal) {
     50 	switch (signal) {
     51 	case SIGCHLD:
     52 		while (waitpid(-1, NULL, WNOHANG) == 0);
     53 		break;
     54 	default:
     55 		exit(EXIT_SUCCESS);
     56 	}
     57 }
     58 
     59 int
     60 read_line(int fd, char *dest, size_t len) {
     61 	size_t	i = 0;
     62 	char	c = 0;
     63 
     64 	do {
     65 		if (read(fd, &c, sizeof(char)) != sizeof(char))
     66 			return 0;
     67 		dest[i++] = c;
     68 	} while (c != '\n' && i < len);
     69 
     70 	dest[i] = '\0';
     71 	return 1;
     72 }
     73 
     74 
     75 int
     76 getsock(struct addrinfo *hints, char *host, char *port) {
     77 	struct addrinfo *ai;
     78 	int sret, sockopt;
     79 	int fd;
     80 
     81 	if ((sret = getaddrinfo(host, port, hints, &ai)) != 0 || ai == NULL)
     82 		die(1, "getaddrinfo() for %s:%s, %s\n", host, port, gai_strerror(sret));
     83 
     84 	fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol);
     85 	sockopt = 1;
     86 	if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (int*)&sockopt, sizeof(int)) == -1)
     87 		die(1, "setsockopt(): %s\n", strerror(errno));
     88 	if (bind(fd, ai->ai_addr, ai->ai_addrlen) == -1)
     89 		die(1, "bind(): %s\n", strerror(errno));
     90 	if (listen(fd, CQUEUE) == -1)
     91 		die(1, "listen(): %s\n", strerror(errno));
     92 
     93 	freeaddrinfo(ai);
     94 
     95 	return fd;
     96 }
     97 
     98 void
     99 mitm(int client, char *host, char *port) {
    100 	struct addrinfo hints;
    101 	struct addrinfo *ai;
    102 	char bufc[NL_TEXTMAX];
    103 	char bufr[NL_TEXTMAX];
    104 	int sret, remote;
    105 	pid_t pid;
    106 
    107 	memset(&hints, 0, sizeof(hints));
    108 	hints.ai_family = AF_UNSPEC;
    109 	hints.ai_socktype = SOCK_STREAM;
    110 
    111 	if ((sret = getaddrinfo(host, port, &hints, &ai)) != 0) {
    112 		die(1, "getaddrinfo(): %s\n", gai_strerror(sret));
    113 		return;
    114 	}
    115 	if ((remote = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) == 1) {
    116 		die(1, "socket(): %s\n", strerror(errno));
    117 		goto cleanup;
    118 	}
    119 	if (connect(remote, ai->ai_addr, ai->ai_addrlen) == -1) {
    120 		die(1, "connect(): %s\n", strerror(errno));
    121 		goto cleanup;
    122 	}
    123 
    124 	switch (pid = fork()) {
    125 	case -1:
    126 		die(1, "fork(): %s\n", errno);
    127 		break;
    128 	case 0:
    129 		while (read_line(client, bufc, sizeof(bufc)) != 0) {
    130 			printf("%03d%s%03d %s", client, CLIENT_STYLE, remote, bufc);
    131 			write(remote, bufc, strlen(bufc));
    132 		}
    133 		exit(EXIT_SUCCESS);
    134 	default:
    135 		while (read_line(remote, bufr, sizeof(bufr)) != 0) {
    136 			printf("%03d%s%03d %s", client, REMOTE_STYLE, remote, bufr);
    137 			write(client, bufr, strlen(bufr));
    138 		}
    139 	}
    140 
    141 cleanup:
    142 	freeaddrinfo(&hints);
    143 	freeaddrinfo(ai);
    144 }
    145 
    146 void
    147 usage(void) {
    148 	fprintf(stderr, "usage: %s [-i myinterface] [-p myport] host port\n", basename(argv0));
    149 	exit(2);
    150 }
    151 
    152 int
    153 main(int argc, char *argv[]) {
    154 	struct sockaddr_storage addr;
    155 	struct addrinfo hints;
    156 	socklen_t addrlen;
    157 	int sock, handle;
    158 	pid_t pid;
    159 
    160 	ARGBEGIN {
    161 	case 'i':
    162 		myhost = EARGF(usage());
    163 		break;
    164 	case 'p':
    165 		myport = EARGF(usage());
    166 		break;
    167 	default:
    168 		usage();
    169 	} ARGEND;
    170 
    171 	if (argc != 2)
    172 		usage();
    173 
    174 	host = argv[0];
    175 	port = argv[1];
    176 
    177 	memset(&hints, 0, sizeof(hints));
    178 	hints.ai_family = AF_UNSPEC;
    179 	hints.ai_flags = AI_PASSIVE;
    180 	hints.ai_socktype = SOCK_STREAM;
    181 	sock = getsock(&hints, myhost, myport);
    182 
    183 	signal(SIGCHLD, sighandler);
    184 
    185 	for (;;) {
    186 		addrlen = sizeof(addr);
    187 		if ((handle = accept(sock, (struct sockaddr *)&addr, &addrlen)) == -1)
    188 			die(1, "accept(): %s\n", strerror(errno));
    189 
    190 		switch (pid = fork()) {
    191 		case -1:
    192 			die(1, "fork(): %s\n", strerror(errno));
    193 			break;
    194 		case 0:
    195 			parent = 0;
    196 			mitm(handle, host, port);
    197 			shutdown(handle, SHUT_RDWR);
    198 			close(handle);
    199 			exit(EXIT_SUCCESS);
    200 		/* parent continue outside loop */
    201 		}
    202 	}
    203 
    204 	return EXIT_SUCCESS;
    205 }