// Microsoft Research Singularity // Copyright (c) Microsoft Corporation. All rights reserved. // // Project: telnet daemon (testing purposs only) // // NOTES / CAVEATS: // - Doesn't echo keyboard input until carriage return. // - Doesn't support control sequences (Ctrl-C, history, etc.) // - Doesn't negotiate. Only works with the Windows XP telent client. // - Doesn't shutdown gracefully. // - Doesn't try to be robust (handle exceptions, etc.) // using System; using System.Diagnostics; using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; namespace telnetd { class Program { private Process p; private byte[] bufOutput; private byte[] bufError; private TcpClient client; private NetworkStream stm; private byte[] bufNet; const byte IAC = 255; // telnet "interpret as command" escape const byte CODE_WILL = 251; // telnet commands const byte CODE_WONT = 252; const byte CODE_DO = 253; const byte CODE_DONT = 254; const byte OPTION_ECHO = 0x01; // telnet command options const byte OPTION_SUPPRESSGA = 0x03; Program(TcpClient c) { client = c; stm = client.GetStream(); } void SendString(string s) { Byte[] data = System.Text.Encoding.ASCII.GetBytes(s); stm.Write(data, 0, data.Length); } void SendOption(byte code, byte option) { byte[] data = new byte[3]; data[0] = IAC; data[1] = code; data[2] = option; stm.Write(data, 0, data.Length); } void ReadOption(out byte code, out byte option) { int b1 = stm.ReadByte(); int b2 = stm.ReadByte(); int b3 = stm.ReadByte(); code = (byte)b2; option = (byte)b3; } void StdOutCallback(IAsyncResult result) { int cb = p.StandardOutput.BaseStream.EndRead(result); if (cb > 0) { stm.Write(bufOutput, 0, cb); } p.StandardOutput.BaseStream.BeginRead(bufOutput, 0, bufOutput.Length, StdOutCallback, null); } void StdErrCallback(IAsyncResult result) { int cb = p.StandardError.BaseStream.EndRead(result); if (cb > 0) { stm.Write(bufError, 0, cb); } p.StandardError.BaseStream.BeginRead(bufError, 0, bufError.Length, StdErrCallback, null); } void NetworkReadCallback(IAsyncResult result) { int cb = stm.EndRead(result); if (cb > 0) { ProcessEscapes(bufNet, cb); string s = System.Text.Encoding.ASCII.GetString(bufNet, 0, cb); p.StandardInput.Write(s); } IAsyncResult res = stm.BeginRead(bufNet, 0, bufNet.Length, NetworkReadCallback, null); } int ProcessEscapes(byte[] buf, int cb) { // TODO: // //for (int i = 0; i < cb; i++) { // if (bufNet[i] == IAC) { // Debug.WriteLine("IAC " + bufNet[i + 1] + " " + bufNet[i + 2]); // } //} // return cb; } void Run() { // Negotiate SendOption(CODE_WILL, OPTION_ECHO); SendOption(CODE_WILL, OPTION_SUPPRESSGA); byte code, option; ReadOption(out code, out option); ReadOption(out code, out option); // Send welcome message SendString("Welcome to the Singularity Telnet Service on "); IPGlobalProperties ipGlobal = IPGlobalProperties.GetIPGlobalProperties(); SendString(ipGlobal.HostName); SendString("\r\n\r\n"); // Create redirected command shell with ansi pipes p = new Process(); p.StartInfo.FileName = "cmd.exe"; p.StartInfo.Arguments = "/A"; p.StartInfo.UseShellExecute = false; p.StartInfo.CreateNoWindow = true; p.StartInfo.RedirectStandardInput = true; p.StartInfo.RedirectStandardOutput = true; p.StartInfo.RedirectStandardError = true; p.Start(); // Begin the async stdio reads bufOutput = new byte[256]; bufError = new byte[256]; p.StandardOutput.BaseStream.BeginRead(bufOutput, 0, bufOutput.Length, StdOutCallback, null); p.StandardError.BaseStream.BeginRead(bufError, 0, bufError.Length, StdErrCallback, null); // Begin the async network reads bufNet = new byte[256]; IAsyncResult res = stm.BeginRead(bufNet, 0, bufNet.Length, NetworkReadCallback, null); // Wait for the shell to exit p.WaitForExit(); client.Close(); } static void Main(string[] args) { // Listen for incoming telnet sessions TcpListener listener = null; try { listener = new TcpListener(IPAddress.Parse("127.0.0.1"), 23); listener.Start(); while (true) { TcpClient c = listener.AcceptTcpClient(); Program p = new Program(c); p.Run(); } } catch (SocketException ex) { Console.WriteLine("SocketException {0}", ex); } finally { if (listener != null) listener.Stop(); } } } }