mirror of
https://git.checksum.fail/alec/erythros
synced 2025-12-10 13:09:55 +02:00
System/Shell/Commands: Add telnet
This commit is contained in:
142
System/Shell/Commands/telnet.HC
Normal file
142
System/Shell/Commands/telnet.HC
Normal file
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user