From a7d55e699e8b9c414563a0cd98f4eb3bc43c76a9 Mon Sep 17 00:00:00 2001 From: Luiz Capitulino Date: Thu, 13 Jan 2011 14:19:51 -0200 Subject: [PATCH] Introduce old redir program Signed-off-by: Luiz Capitulino --- redir/Makefile | 6 ++ redir/redir.c | 199 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+) create mode 100644 redir/Makefile create mode 100644 redir/redir.c diff --git a/redir/Makefile b/redir/Makefile new file mode 100644 index 0000000..bd8c3b1 --- /dev/null +++ b/redir/Makefile @@ -0,0 +1,6 @@ + +redir: redir.c + $(CC) -Wall -o $@ $+ + +clean: + rm -f redir *~ *.o diff --git a/redir/redir.c b/redir/redir.c new file mode 100644 index 0000000..d0161df --- /dev/null +++ b/redir/redir.c @@ -0,0 +1,199 @@ +/* + * Simple TCP redirector + * + * Luiz Fernando N. Capitulino + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static void die(const char *s) +{ + perror(s); + exit(1); +} + +static void help(void) +{ + printf("redir : :\n"); + exit(1); +} + +static void cleanup_child(int signr) +{ + wait(NULL); +} + +static int read_user_addr(struct sockaddr_in *addr, const char *addr_str) +{ + int ret = -1; + char *p, *addr_str2; + + addr_str2 = strdup(addr_str); + p = strchr(addr_str2, ':'); + if (!p) { + goto out; + } + + *p = '\0'; + if (!inet_aton(addr_str2, &addr->sin_addr)) { + goto out; + } + + p++; + if (p == '\0') { + goto out; + } + + addr->sin_port = htons(strtol(p, NULL, 10)); + addr->sin_family = AF_INET; + ret = 0; + +out: + free(addr_str2); + return ret; +} + +static int redir(int sfd, int dfd) +{ + unsigned char buf[4096]; + size_t count, total, idx; + + memset(buf, 0, sizeof(buf)); + + count = read(sfd, buf, sizeof(buf)); + if (!count) { + return 1; + } + + idx = 0; + total = count; + for (;;) { + count = write(dfd, buf + idx, total); + if (count < 0) { + die("write()"); + } + + total -= count; + if (!total) { + return 0; + } + idx += count; + } +} + +static void handle_new_client(int cfd, struct sockaddr_in *client_add, + struct sockaddr_in *dest_addr) +{ + int ret, dfd, nfds; + + dfd = socket(AF_INET, SOCK_STREAM, 0); + if (dfd < 0) { + die("socket()"); + } + + ret = connect(dfd, (struct sockaddr *) dest_addr, + sizeof(struct sockaddr_in)); + if (dfd < 0) { + die("connect()"); + } + + nfds = cfd >= dfd ? cfd : dfd; + for (;;) { + fd_set rfds; + + FD_ZERO(&rfds); + FD_SET(cfd, &rfds); + FD_SET(dfd, &rfds); + + ret = select(nfds + 1, &rfds, NULL, NULL, 0); + if (ret < 0) { + die("select()"); + } else if (FD_ISSET(cfd, &rfds)) { + if (redir(cfd, dfd)) { + return; + } + } else if (FD_ISSET(dfd, &rfds)) { + if (redir(dfd, cfd)) { + return; + } + } else { + abort(); + } + } + + close(dfd); +} + +int main(int argc, const char *argv[]) +{ + struct sockaddr_in src_addr, dest_addr, client_addr; + socklen_t dest_addr_sz; + int err, sfd, cfd; + + if (argc != 3) { + help(); + } + + err = read_user_addr(&src_addr, argv[1]); + if (err) { + help(); + } + + err = read_user_addr(&dest_addr, argv[2]); + if (err) { + help(); + } + + signal(SIGCHLD, cleanup_child); + + sfd = socket(AF_INET, SOCK_STREAM, 0); + if (sfd < 0) { + die("socket()"); + } + + err = bind(sfd, (struct sockaddr *) &src_addr, sizeof(struct sockaddr_in)); + if (err) { + die("bind()"); + } + + err = listen(sfd, 2); + if (err) { + die("listen()"); + } + + for (;;) { + pid_t pid; + + dest_addr_sz = sizeof(struct sockaddr_in); + cfd = accept(sfd, (struct sockaddr *) &client_addr, &dest_addr_sz); + if (cfd < 0) { + die("accept()"); + } + + fprintf(stderr, "-> New connection from: %s:%d\n", + inet_ntoa(client_addr.sin_addr), ntohs(client_addr.sin_port)); + + pid = fork(); + if (pid < 0) { + perror("fork()"); + } else if (pid == 0) { + /* child */ + handle_new_client(cfd, &client_addr, &dest_addr); + exit(0); + } + + /* parent */ + close(cfd); + } + + return 0; +} -- 2.11.4.GIT