Files
erythros/System/Shell/Commands/telnet.HC
2025-09-19 17:49:41 -04:00

142 lines
3.3 KiB
HolyC

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