#include #include #include #include #include #include #include #include #include #include #include "libtelnet.h" static int server_sock; static int client_sock; static struct libtelnet_t server_telnet; static struct libtelnet_t client_telnet; static const char *get_name(int sock) { if (sock == server_sock) return "\e[31mSERVER"; else return "\e[34mCLIENT"; } static const char *get_cmd(unsigned char cmd) { static char buffer[4]; switch (cmd) { case 255: return "IAC"; case 254: return "DONT"; case 253: return "DO"; case 252: return "WONT"; case 251: return "WILL"; case 250: return "SB"; case 249: return "GA"; case 248: return "EL"; case 247: return "EC"; case 246: return "AYT"; case 245: return "AO"; case 244: return "IP"; case 243: return "BREAK"; case 242: return "DM"; case 241: return "NOP"; case 240: return "SE"; case 239: return "EOR"; case 238: return "ABORT"; case 237: return "SUSP"; case 236: return "xEOF"; default: snprintf(buffer, sizeof(buffer), "%d", (int)cmd); return buffer; } } static const char *get_opt(unsigned char opt) { switch (opt) { case 0: return "BINARY"; case 1: return "ECHO"; case 2: return "RCP"; case 3: return "SGA"; case 4: return "NAMS"; case 5: return "STATUS"; case 6: return "TM"; case 7: return "RCTE"; case 8: return "NAOL"; case 9: return "NAOP"; case 10: return "NAOCRD"; case 11: return "NAOHTS"; case 12: return "NAOHTD"; case 13: return "NAOFFD"; case 14: return "NAOVTS"; case 15: return "NAOVTD"; case 16: return "NAOLFD"; case 17: return "XASCII"; case 18: return "LOGOUT"; case 19: return "BM"; case 20: return "DET"; case 21: return "SUPDUP"; case 22: return "SUPDUPOUTPUT"; case 23: return "SNDLOC"; case 24: return "TTYPE"; case 25: return "EOR"; case 26: return "TUID"; case 27: return "OUTMRK"; case 28: return "TTYLOC"; case 29: return "3270REGIME"; case 30: return "X3PAD"; case 31: return "NAWS"; case 32: return "TSPEED"; case 33: return "LFLOW"; case 34: return "LINEMODE"; case 35: return "XDISPLOC"; case 36: return "ENVIRON"; case 37: return "AUTHENTICATION"; case 38: return "ENCRYPT"; case 39: return "NEW-ENVIRON"; case 70: return "MSSP"; case 85: return "COMPRESS"; case 86: return "COMPRESS2"; case 93: return "ZMP"; case 255: return "EXOPL"; default: return "unknown"; } } static struct libtelnet_t *other_telnet(struct libtelnet_t *telnet) { if (telnet == &server_telnet) return &client_telnet; else return &server_telnet; } static void* other_socket(int sock) { if (sock == server_sock) return (void*)&client_sock; else return (void*)&server_sock; } static void print_buffer(unsigned char *buffer, unsigned int size) { unsigned int i; for (i = 0; i != size; ++i) { if (buffer[i] == ' ' || (isprint(buffer[i]) && !isspace(buffer[i]))) printf("%c", (char)buffer[i]); else if (buffer[i] == '\n') printf("<%02X>\n", (int)buffer[i]); else printf("<%02X>", (int)buffer[i]); } } void libtelnet_data_cb(struct libtelnet_t *telnet, unsigned char *buffer, unsigned int size, void *user_data) { int sock = *(int*)user_data; printf("%s DATA: ", get_name(sock)); print_buffer(buffer, size); printf("\e[0m\n"); libtelnet_send_data(other_telnet(telnet), buffer, size, other_socket(sock)); } void libtelnet_send_cb(struct libtelnet_t *telnet, unsigned char *buffer, unsigned int size, void *user_data) { int sock = *(int*)user_data; /* DONT SPAM printf("%s SEND: ", get_name(sock)); print_buffer(buffer, size); printf("\e[0m\n"); */ /* send data */ send(sock, buffer, size, 0); } void libtelnet_command_cb(struct libtelnet_t *telnet, unsigned char cmd, void *user_data) { int sock = *(int*)user_data; printf("%s IAC %s\e[0m\n", get_name(sock), get_cmd(cmd)); libtelnet_send_command(other_telnet(telnet), cmd, other_socket(sock)); } void libtelnet_negotiate_cb(struct libtelnet_t *telnet, unsigned char cmd, unsigned char opt, void *user_data) { int sock = *(int*)user_data; printf("%s IAC %s %d (%s)\e[0m\n", get_name(sock), get_cmd(cmd), (int)opt, get_opt(opt)); libtelnet_send_negotiate(other_telnet(telnet), cmd, opt, other_socket(sock)); } void libtelnet_subrequest_cb(struct libtelnet_t *telnet, unsigned char type, unsigned char *buffer, unsigned int size, void *user_data) { int sock = *(int*)user_data; printf("%s SUB %d (%s)", get_name(sock), (int)type, get_opt(type)); if (size > 0) { printf(": "); print_buffer(buffer, size); } printf("\e[0m\n"); libtelnet_send_subrequest(other_telnet(telnet), type, buffer, size, other_socket(sock)); } void libtelnet_error_cb(struct libtelnet_t *telnet, enum libtelnet_error_t error, void *user_data) { int sock = *(int*)user_data; printf("%s ERROR: %d\e[0m\n", get_name(sock), (int)error); } int main(int argc, char **argv) { unsigned char buffer[512]; int listen_sock; int rs; struct sockaddr_in addr; socklen_t addrlen; struct pollfd pfd[2]; /* check usage */ if (argc != 4) { fprintf(stderr, "Usage:\n ./telnet-proxy \n"); return 1; } /* create listening socket */ if ((listen_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "socket() failed: %s\n", strerror(errno)); return 1; } /* re-use addr */ rs = 1; setsockopt(listen_sock, SOL_SOCKET, SO_REUSEADDR, &rs, sizeof(rs)); /* bind */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(strtol(argv[3], 0, 10)); if (bind(listen_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { fprintf(stderr, "bind() failed: %s\n", strerror(errno)); return 1; } /* listen */ if (listen(listen_sock, 5) == -1) { fprintf(stderr, "listen() failed: %s\n", strerror(errno)); return 1; } /* wait for client connection */ if ((client_sock = accept(listen_sock, (struct sockaddr *)&addr, &addrlen)) == -1) { fprintf(stderr, "accept() failed: %s\n", strerror(errno)); return 1; } /* create server socket */ if ((server_sock = socket(AF_INET, SOCK_STREAM, 0)) == -1) { fprintf(stderr, "socket() failed: %s\n", strerror(errno)); return 1; } /* bind */ memset(&addr, 0, sizeof(addr)); addr.sin_family = AF_INET; if (bind(server_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { fprintf(stderr, "bind() failed: %s\n", strerror(errno)); return 1; } /* connect */ memset(&addr, 0, sizeof(addr)); if (inet_pton(AF_INET, argv[1], &addr.sin_addr) != 1) { fprintf(stderr, "inet_pton() failed: %s\n", strerror(errno)); return 1; } addr.sin_family = AF_INET; addr.sin_port = htons(strtol(argv[2], 0, 10)); if (connect(server_sock, (struct sockaddr *)&addr, sizeof(addr)) == -1) { fprintf(stderr, "server() failed: %s\n", strerror(errno)); return 1; } /* initialize telnet boxes */ libtelnet_init(&server_telnet); libtelnet_init(&client_telnet); /* initialize poll descriptors */ memset(pfd, 0, sizeof(pfd)); pfd[0].fd = server_sock; pfd[0].events = POLLIN | POLLHUP; pfd[1].fd = client_sock; pfd[1].events = POLLIN | POLLHUP; /* loop while both connections are open */ while (poll(pfd, 2, -1) != -1) { /* read from server */ if (pfd[0].revents & POLLIN) { if ((rs = recv(pfd[0].fd, buffer, sizeof(buffer), 0)) > 0) libtelnet_push(&server_telnet, buffer, rs, (void*)&pfd[0].fd); } if (pfd[0].revents & POLLHUP) break; /* read from client */ if (pfd[1].revents & POLLIN) { if ((rs = recv(pfd[1].fd, buffer, sizeof(buffer), 0)) > 0) libtelnet_push(&client_telnet, buffer, rs, (void*)&pfd[1].fd); } if (pfd[1].revents & POLLHUP) break; } /* clean up */ libtelnet_free(&server_telnet); libtelnet_free(&client_telnet); close(server_sock); close(client_sock); close(listen_sock); return 0; }