// 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; }