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 }