From 84e0e3974b69c8cdff88d7045ae2a4dc423848e8 Mon Sep 17 00:00:00 2001 From: Michiel Broek Date: Sat, 31 Jan 2004 22:15:00 +0000 Subject: [PATCH] Added experimental telnet outbound code --- ChangeLog | 4 + TODO | 2 + lib/libs.h | 1 + mbcico/call.c | 8 +- mbcico/mbcico.c | 6 + mbcico/opentcp.c | 319 +++++++++++++++++++++++++++++++++++++++++------ mbcico/opentcp.h | 7 ++ mbcico/session.c | 5 + 8 files changed, 313 insertions(+), 39 deletions(-) diff --git a/ChangeLog b/ChangeLog index 39876e1b..559d13e9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,10 @@ $Id$ v0.39.9 29-Jan-2004 + mbcico: + Added experimental code for telnet outbound connections. This + code is not compiled by default so don't worry or bother. + v0.39.8 26-Jan-2004 - 29-Jan-2004 diff --git a/TODO b/TODO index 7991d397..3cdbb8c6 100644 --- a/TODO +++ b/TODO @@ -124,6 +124,8 @@ mbcico: N: Implement PLZ turn off m_get command. + N: Make workaround for binkp bug in Irex 2.24 upto 2.29 + mbfile: L: Add a check to see if the magic filenames are (still) valid. diff --git a/lib/libs.h b/lib/libs.h index 668ae381..4b87f30b 100644 --- a/lib/libs.h +++ b/lib/libs.h @@ -86,6 +86,7 @@ #ifdef HAVE_ZLIB_H #include #endif +#include #pragma pack(1) diff --git a/mbcico/call.c b/mbcico/call.c index 7881eed8..12111f85 100644 --- a/mbcico/call.c +++ b/mbcico/call.c @@ -181,9 +181,11 @@ int call(faddr *addr) tcp_mode = TCPMODE_IBN; } else if (strcmp(protocol, "fido") == 0) { tcp_mode = TCPMODE_IFC; -// } else if (strcmp(protocol, "telnet") == 0) { -// tcp_mode = TCPMODE_ITN; -// telnet = TRUE; +#ifdef USE_EXPERIMENT + } else if (strcmp(protocol, "telnet") == 0) { + tcp_mode = TCPMODE_ITN; + telnet = TRUE; +#endif } else { Syslog('+', "No common TCP/IP protocols for node %s", nlent->name); free(inetaddr); diff --git a/mbcico/mbcico.c b/mbcico/mbcico.c index d6146be8..ca364a20 100644 --- a/mbcico/mbcico.c +++ b/mbcico/mbcico.c @@ -369,11 +369,17 @@ int main(int argc, char *argv[]) /* * Slave (answer) mode */ +#ifdef USE_EXPERIMENT + if (telnet) { + Syslog('-', "Will use experimental telnet code"); + } +#else if (telnet) { WriteError("Answering calls with the \"-t itn\" option no longer supported"); WriteError("Install mbtelind to answer incoming telnet calls"); die(MBERR_COMMANDLINE); } +#endif if (!answermode && tcp_mode == TCPMODE_IBN) answermode = xstrcpy((char *)"ibn"); rc = maxrc = answer(answermode); diff --git a/mbcico/opentcp.c b/mbcico/opentcp.c index cc472306..d958fee5 100644 --- a/mbcico/opentcp.c +++ b/mbcico/opentcp.c @@ -61,6 +61,13 @@ extern long rcvdbytes; extern int Loaded; static int tcp_is_open = FALSE; +#ifdef USE_EXPERIMENT +void telnet_init(int); +void telnet_answer(int, int, int); +void telout_filter(int [], int); +void telin_filter(int [], int); +#endif + /* opentcp() was rewritten by Martin Junius */ @@ -68,10 +75,12 @@ int opentcp(char *name) { struct servent *se; struct hostent *he; - int a1, a2, a3, a4, Fd, GotPort = FALSE; + struct sockaddr_in server; + int a1, a2, a3, a4, rc, Fd, Fdo, GotPort = FALSE; char *errmsg, *portname; short portnum; - struct sockaddr_in server; + int input_pipe[2], output_pipe[2]; + pid_t fpid; Syslog('+', "Open TCP connection to \"%s\"", MBSE_SS(name)); @@ -102,11 +111,13 @@ int opentcp(char *name) else server.sin_port = htons(FIDOPORT); break; -// case TCPMODE_ITN: if ((se = getservbyname("telnet", "tcp"))) -// server.sin_port = se->s_port; -// else -// server.sin_port = htons(TELNPORT); -// break; +#ifdef USE_EXPERIMENT + case TCPMODE_ITN: if ((se = getservbyname("telnet", "tcp"))) + server.sin_port = se->s_port; + else + server.sin_port = htons(TELNPORT); + break; +#endif case TCPMODE_IBN: if ((se = getservbyname("binkd", "tcp"))) server.sin_port = se->s_port; else @@ -134,38 +145,134 @@ int opentcp(char *name) return -1; } - Syslog('d', "SIGPIPE => sigpipe()"); - signal(SIGPIPE, sigpipe); - Syslog('d', "SIGHUP => linedrop()"); - signal(SIGHUP, linedrop); - fflush(stdin); - fflush(stdout); - setbuf(stdin,NULL); - setbuf(stdout,NULL); - close(0); - close(1); - if ((Fd = socket(AF_INET,SOCK_STREAM,0)) != 0) { - WriteError("$Cannot create socket (got %d, expected 0"); - open("/dev/null",O_RDONLY); - open("/dev/null",O_WRONLY); - return -1; - } - if (dup(Fd) != 1) { - WriteError("$Cannot dup socket"); - open("/dev/null",O_WRONLY); - return -1; - } - clearerr(stdin); - clearerr(stdout); - if (connect(Fd,(struct sockaddr *)&server,sizeof(server)) == -1) { - Syslog('+', "Cannot connect %s",inet_ntoa(server.sin_addr)); - return -1; - } +#ifdef USE_EXPERIMENT + if (tcp_mode == TCPMODE_ITN) { + Syslog('s', "Installing telnet filter..."); - f_flags=0; + Syslog('d', "SIGPIPE => sigpipe()"); + signal(SIGPIPE, sigpipe); + Syslog('d', "SIGHUP => linedrop()"); + signal(SIGHUP, linedrop); + + /* + * Create TCP socket and open + */ + if ((Fdo = socket(AF_INET,SOCK_STREAM,0)) == -1) { + WriteError("$Cannot create socket"); + return -1; + } + if (connect(Fdo,(struct sockaddr *)&server,sizeof(server)) == -1) { + Syslog('+', "Cannot connect %s",inet_ntoa(server.sin_addr)); + return -1; + } + Syslog('s', "socket %d", Fdo); + + fflush(stdin); + fflush(stdout); + setbuf(stdin,NULL); + setbuf(stdout, NULL); + close(0); + close(1); + + /* + * Create output pipe + */ + if ((rc = pipe(output_pipe)) == -1) { + WriteError("$could not create output_pipe"); + return -1; + } + + fpid = fork(); + switch (fpid) { + case -1: WriteError("fork for telout_filter failed"); + return -1; + case 0: if (close(output_pipe[1]) == -1) { + WriteError("$error close output_pipe[1]"); + return -1; + } + telout_filter(output_pipe, Fdo); + /* NOT REACHED */ + } + if (close(output_pipe[0] == -1)) { + WriteError("$error close output_pipe[0]"); + return -1; + } + Syslog('s', "telout_filter forked with pid %d", fpid); + + /* + * Create input pipe + */ + if ((rc = pipe(input_pipe)) == -1) { + WriteError("$could not create input_pipe"); + return -1; + } + + /* + * Fork input filter + */ + fpid = fork(); + switch (fpid) { + case -1: WriteError("fork for telin_filter failed"); + return -1; + case 0: if (close(input_pipe[0]) == -1) { + WriteError("$error close input_pipe[0]"); + return -1; + } + telin_filter(input_pipe, Fdo); + /* NOT REACHED */ + } + if (close(input_pipe[1]) == -1) { + WriteError("$error close input_pipe[1]"); + return -1; + } + Syslog('s', "telin_filter forked with pid %d", fpid); + Syslog('s', "stdout = %d", output_pipe[1]); + Syslog('s', "stdin = %d", input_pipe[0]); + + telnet_init(Fdo); + f_flags=0; + + } else { +#endif + /* + * Transparant 8 bits connection + */ + Syslog('d', "SIGPIPE => sigpipe()"); + signal(SIGPIPE, sigpipe); + Syslog('d', "SIGHUP => linedrop()"); + signal(SIGHUP, linedrop); + fflush(stdin); + fflush(stdout); + setbuf(stdin,NULL); + setbuf(stdout,NULL); + close(0); + close(1); + + if ((Fd = socket(AF_INET,SOCK_STREAM,0)) != 0) { + WriteError("$Cannot create socket (got %d, expected 0)", Fd); + open("/dev/null",O_RDONLY); + open("/dev/null",O_WRONLY); + return -1; + } + if (dup(Fd) != 1) { + WriteError("$Cannot dup socket"); + open("/dev/null",O_WRONLY); + return -1; + } + clearerr(stdin); + clearerr(stdout); + if (connect(Fd,(struct sockaddr *)&server,sizeof(server)) == -1) { + Syslog('+', "Cannot connect %s",inet_ntoa(server.sin_addr)); + return -1; + } + + f_flags=0; +#ifdef USE_EXPERIMENT + } +#endif Syslog('+', "Established %s/TCP connection with %s, port %d", - (tcp_mode == TCPMODE_IFC) ? "IFC":(tcp_mode == TCPMODE_IBN) ? "IBN":"Unknown", + (tcp_mode == TCPMODE_IFC) ? "IFC":(tcp_mode == TCPMODE_ITN) ?"ITN":(tcp_mode == TCPMODE_IBN) ? "IBN":"Unknown", inet_ntoa(server.sin_addr), (int)ntohs(server.sin_port)); c_start = time(NULL); carrier = TRUE; @@ -183,6 +290,14 @@ void closetcp(void) if (!tcp_is_open) return; +#ifdef USE_EXPERIMENT + if (tcp_mode == TCPMODE_ITN) { + /* + * Check if telout thread is running + */ + } +#endif + shutdown(fd, 2); Syslog('d', "SIGHUP => SIG_IGN"); signal(SIGHUP, SIG_IGN); @@ -218,3 +333,135 @@ void closetcp(void) } + +#ifdef USE_EXPERIMENT + + +void telnet_init(int Fd) +{ + Syslog('s', "telnet_init(%d)", Fd); + telnet_answer(DO, TOPT_SUPP, Fd); + telnet_answer(WILL, TOPT_SUPP, Fd); + telnet_answer(DO, TOPT_BIN, Fd); + telnet_answer(WILL, TOPT_BIN, Fd); + telnet_answer(DO, TOPT_ECHO, Fd); + telnet_answer(WILL, TOPT_ECHO, Fd); +} + + + +void telnet_answer(int tag, int opt, int Fd) +{ + char buf[3]; + char *r = (char *)"???"; + + switch (tag) { + case WILL: r = (char *)"WILL"; + break; + case WONT: r = (char *)"WONT"; + break; + case DO: r = (char *)"DO"; + break; + case DONT: r = (char *)"DONT"; + break; + } + Syslog('s', "Telnet: send %s %d", r, opt); + + buf[0] = IAC; + buf[1] = tag; + buf[2] = opt; + if (write (Fd, buf, 3) != 3) + WriteError("$answer cant send"); +} + + + +void telout_filter(int output_pipe[], int Fd) +{ + int rc, c; + char ch; + + Syslog('s', "telout_filter: in=%d out=%d", output_pipe[0], Fd); + + while (read(output_pipe[0], &ch, 1) > 0) { + c = (int)ch & 0xff; +// Syslog('s', "telout_filter: ch=%s", printablec(c)); + if (c == IAC) { + Syslog('s', "telout_filter: got IAC"); + /* + * Escape IAC characters + */ + rc = write(Fd, &ch, 1); + } + /* write translated character back to user_handler. */ + rc = write(Fd, &ch, 1); + if (rc == -1) { /* write failed - notify user and exit. */ + Syslog('s', "$telout_filter: write to Fd failed"); + exit(1); + } + } + Syslog('s', "$telout_filter: read error"); + + exit(0); +} + + +void telin_filter(int input_pipe[], int Fd) +{ + int rc, c, m; + char ch; + + Syslog('s', "telin_filter: in=%d out=%d", Fd, input_pipe[1]); + Syslog('s', "telin_filter: IAC=%s %d", printablec(IAC), IAC); + + while (read(Fd, &ch, 1) > 0) { + c = (int)ch & 0xff; +// Syslog('s', "telin_filter: ch=%s", printablec(c)); + if (c == IAC) { + Syslog('s', "got IAC"); + if ((read(Fd, &ch, 1) < 0)) + break; + m = (int)ch & 0xff; + switch (m) { + case WILL: read(Fd, &ch, 1); + m = (int)ch & 0xff; + Syslog('s', "Telnet: recv WILL %d", m); + if (m != TOPT_BIN && m != TOPT_SUPP && m != TOPT_ECHO) + telnet_answer(DONT, m, input_pipe[1]); + break; + case WONT: read(Fd, &ch, 1); + m = (int)ch & 0xff; + Syslog('s', "Telnet: recv WONT %d", m); + break; + case DO: read(Fd, &ch, 1); + m = (int)ch & 0xff; + Syslog('s', "Telnet: recv DO %d", m); + if (m != TOPT_BIN && m != TOPT_SUPP && m != TOPT_ECHO) + telnet_answer(WONT, m, input_pipe[1]); + break; + case DONT: read(Fd, &ch, 1); + m = (int)ch & 0xff; + Syslog('s', "Telnet: recv DONT %d", m); + break; + case IAC: ch = (char)m & 0xff; + rc = write(input_pipe[1], &ch, 1); + break; + default: Syslog('s', "Telnet: recv IAC %d, not good", m); + break; + } + } else { +// Syslog('s', "Telnet: normal"); + ch = (char)c; + rc = write(input_pipe[1], &ch, 1); + if (rc == -1) { /* write failed - notify user and exit. */ + Syslog('s', "$telin_filter: write to input_pipe[1] failed"); + exit(1); + } + } + } + Syslog('s', "$telin_filter: read error"); + + exit(0); +} + +#endif diff --git a/mbcico/opentcp.h b/mbcico/opentcp.h index 9e8d9e94..ed045d8c 100644 --- a/mbcico/opentcp.h +++ b/mbcico/opentcp.h @@ -3,6 +3,13 @@ #ifndef _OPENTCP_H #define _OPENTCP_H +#define MBT_TIMEOUT 500 +#define MBT_BUFLEN 8192 + +#define TOPT_BIN 0 +#define TOPT_ECHO 1 +#define TOPT_SUPP 3 + int opentcp(char *); void closetcp(void); diff --git a/mbcico/session.c b/mbcico/session.c index 1d040b50..e84c5089 100644 --- a/mbcico/session.c +++ b/mbcico/session.c @@ -110,6 +110,11 @@ int session(faddr *a, node *nl, int role, int tp, char *dt) } } session_flags |= SESSION_TCP; +#ifdef USE_EXPERIMENT + if ((tcp_mode == TCPMODE_ITN) && (role == 0)) { + Syslog('-', "Will need to install telnet receiver thread"); + } +#endif } if (data)