diff --git a/System/Shell/Commands/telnet.HC b/System/Shell/Commands/telnet.HC new file mode 100644 index 0000000..a589ca6 --- /dev/null +++ b/System/Shell/Commands/telnet.HC @@ -0,0 +1,142 @@ +// A very dumb, not-quite-Telnet program for testing purposes +// If running from a VM, on the host you can do something like: + +// socat TCP-LISTEN:2323,bind=10.20.0.254,reuseaddr,fork EXEC:"/bin/bash",pty,stderr,setsid,sigint,sane + +// and connect to the host from Erythros with "telnet 10.20.0.254 2323" + +#define TELNET_WILL 251 +#define TELNET_WONT 252 +#define TELNET_DO 253 +#define TELNET_DONT 254 +#define TELNET_IAC 255 + +#define TELNET_CONNECTION_TIMED_OUT cnts.jiffies > ts_begin + ts_timeout + +class TelnetSession { + @shell* sh; + TlsSocket* s; +}; + +I64 @telnet_ignore_commands(U8* buf) +{ + I64 i = 0; + while (buf[i] == TELNET_IAC) { + switch (buf[i + 1]) { + case TELNET_WILL: + case TELNET_WONT: + buf[i + 1] = TELNET_DONT; + break; + case TELNET_DO: + case TELNET_DONT: + buf[i + 1] = TELNET_WONT; + break; + } + i += 3; + } + return i; +} + +U0 @telnet_session(TelnetSession* session) +{ + U8 chars[1040]; + U8* buf = &chars; + I64 cnt = 1; + I64 i; + + while (cnt && session->s->state != TCP_SOCKET_STATE_CLOSED) { + cnt = session->s->receive(buf, 1024); + if (cnt) { + buf[cnt] = NULL; + i = 0; + while (i < cnt) { + switch (buf[i]) { + case TELNET_IAC: + i += @telnet_ignore_commands(buf); + session->s->send(buf, i); + buf += i; + break; + default: + Stdio.WriteLine(session->sh, buf); + i = cnt; + break; + } + } + } + Sleep(1); + } +} + +U0 @telnet_handle_input(@shell* sh, TlsSocket* s) +{ + U8 buf[128]; + I64 len = 0; + while (FifoU8Cnt(sh->input)) + FifoU8Rem(sh->input, buf + len++); + if (len) + s->send(buf, len); +} + +I64 @shell_cmd_telnet(@shell* sh, I64 argc, U8** argv) +{ + if (argc < 2) { + Stdio.WriteLine(sh, "Usage: telnet host [port]\n"); + return 1; + } + + U8 buf[128]; + U8* host = argv[1]; + I64 port = 23; + if (argc > 2) { + port = Str2I64(argv[2]); + } + + I64 ts_begin = 0; + I64 ts_timeout = 10000; + + if (!host || !StrLen(host)) { + Stdio.WriteLine(sh, "telnet: Invalid host specified\n"); + return 1; + } + + if (@dns_query(host) == U32_MAX) { + Stdio.WriteLine(sh, "telnet: Host not found: %s\n", host); + return 1; + } + + StrPrint(buf, "Trying %s port %d...\n", host, port); + Stdio.WriteLine(sh, buf); + + TelnetSession session; + session.sh = sh; + session.s = @tcp_socket_create(host, port); + ts_begin = cnts.jiffies; + + while (!sh->break && session.s->state != TCP_SOCKET_STATE_ESTABLISHED && !(TELNET_CONNECTION_TIMED_OUT)) { + Sleep(1); + } + + if (sh->break) { + session.s->close(); + return 1; + } + + if (TELNET_CONNECTION_TIMED_OUT) { + Stdio.WriteLine(sh, "Connection timed out.\n"); + session.s->close(); + return 1; + } + + StrPrint(buf, "Connected to %s.\n", host); + Stdio.WriteLine(sh, buf); + + Spawn(&@telnet_session, &session); + + while (session.s->state != TCP_SOCKET_STATE_CLOSED) { + @telnet_handle_input(sh, session.s); + Sleep(1); + } + + Stdio.WriteLine(sh, "Connection closed by foreign host.\n"); + return 1; +} \ No newline at end of file