#include #include #include #include #include #include #include #include #include #include "proxy.h" static int parse_host(const char *host, const char *port, struct addrinfo **addr) { struct addrinfo hints = { .ai_family = AF_UNSPEC, .ai_socktype = SOCK_STREAM, .ai_flags = AI_PASSIVE, }; int err; if ((err = getaddrinfo(host, port, &hints, addr))) { fprintf(stderr, "getaddrinfo failed: %s\n", gai_strerror(err)); return -1; } return 0; } static int listen_source(struct addrinfo *source) { int fd = -1; for (struct addrinfo *a = source; a; a = a->ai_next) { if ((fd = socket(a->ai_family, a->ai_socktype, a->ai_protocol)) == -1) continue; if (!bind(fd, a->ai_addr, a->ai_addrlen) && !listen(fd, 1)) break; close(fd); fd = -1; } return fd; } static int connect_target(struct addrinfo *target) { int fd = -1; for (struct addrinfo *a = target; a; a = a->ai_next) { if ((fd = socket(a->ai_family, a->ai_socktype, a->ai_protocol)) == -1) continue; if (connect(fd, a->ai_addr, a->ai_addrlen) != -1) break; close(fd); fd = -1; } return fd; } struct args { struct addrinfo *source; struct addrinfo *target; unsigned delay; }; static void usage(const char *progname) { int width = 20; const char *args[] = { "-d DELAY", "millisecond delay to add (default: 500ms)", "-p LOCALPORT", "port to listen on (default: 1234)", NULL }; fprintf(stderr, "usage: %s [-d DELAY] [-p LOCALPORT] HOST PORT\n\n", progname); for (const char **a = args; *a; a += 2) fprintf(stderr, "\t%-*s %s\n", width, a[0], a[1]); } static int parse_unsigned(const char *arg, unsigned *out) { char *end; errno = 0; unsigned long val = strtoul(arg, &end, 10); if (*end) return -1; if (errno && !val) return -1; if (val == ULONG_MAX && errno == ERANGE) return -1; if (val > UINT_MAX) return -1; *out = val; return 0; } static int parse_args(struct args *args, int argc, char **argv) { args->delay = 500; const char *localport = "1234"; const char *host = NULL, *port = NULL; extern char *optarg; extern int optind; int opt, error = 0; while ((opt = getopt(argc, argv, "+d:p:")) != -1) { switch (opt) { case 'd': if (parse_unsigned(optarg, &args->delay)) { fprintf(stderr, "invalid delay\n"); error = 1; } break; case 'p': localport = optarg; break; default: error = 1; } } if (optind <= argc - 2) { host = argv[optind++]; port = argv[optind++]; } else error = 1; if (error) { usage(argv[0]); return -1; } if (parse_host(NULL, localport, &args->source)) return -1; if (parse_host(host, port, &args->target)) return -1; return 0; } int main(int argc, char **argv) { struct args args; if (parse_args(&args, argc, argv)) return -1; int listenfd = listen_source(args.source); if (listenfd < 0) { perror("listen_source"); return -1; } for (;;) { int sourcefd = accept(listenfd, NULL, NULL); if (sourcefd == -1) break; int targetfd = connect_target(args.target); if (targetfd == -1) { perror("connect_target"); close(sourcefd); break; } proxy(sourcefd, targetfd, args.delay); close(targetfd); close(sourcefd); } close(listenfd); return 0; }