Ejemplo n.º 1
0
 private void DestinationWrite(Stream destination, byte[] buffer, int count, CommPacketDirection direction)
 {
     Application.Current.Dispatcher.Invoke(() =>
     {
         ProxyUiWindow.WriteBytes(buffer, count, direction, m_connectionInstance);
     });
     TryWriteStream(destination, buffer, 0, count, direction == CommPacketDirection.ServerToClient);
 }
        private void Window_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (Data.ShutdownStarted)
            {
                if (!shutdownCompleted)
                {
                    e.Cancel = true;
                }

                return;
            }

            e.Cancel             = true;
            Data.ShutdownStarted = true;

            ProxyUiWindow.CloseInstance();
            SettingsWindow.CloseInstance();

            ComponentEngine.Instance.Stop().ContinueWith(bla =>
            {
                Dispatcher.BeginInvoke(new Action(() =>
                {
                    if (bla.Result.Count > 0)
                    {
                        MessageBox.Show($"The following errors occured while trying to restore your system:\r\n{string.Join("\r\n", bla.Result)}", "Shutdown Errors", MessageBoxButton.OK, MessageBoxImage.Warning);
                    }

                    shutdownCompleted = true;
                    Close();

                    Task.Run(async() =>
                    {
                        await Task.Delay(5000);
                        Application.Current.Shutdown(0);
                    });
                }));
            });
        }
Ejemplo n.º 3
0
        /// <summary>
        /// Begins the UDP MITM. RemotePort must be set before calling this
        /// </summary>
        /// <returns></returns>
        public async Task StartAsync()
        {
            // Client to send data to the server
            UdpClient sender = new UdpClient();

            // Endpoint representing the local port
            var endpoint = new IPEndPoint(IPAddress.Any, LocalPort);

            try
            {
                // Local function called when data is received
                void requestCallback(IAsyncResult ar)
                {
                    try
                    {
                        // Complete the receive and get the bytes
                        var bytes = m_listener.EndReceive(ar, ref endpoint);

                        // Send the bytes to the server
                        if (RemotePort != 0)
                        {
                            InstanceAdded = true;

                            Application.Current.Dispatcher.Invoke(() =>
                            {
                                ProxyUiWindow.SendBytesToUi(m_connectionInstance, new CommPacket
                                {
                                    Data         = bytes,
                                    Direction    = CommPacketDirection.ClientToServer,
                                    Id           = Guid.NewGuid(),
                                    Instance     = m_connectionInstance,
                                    ParentPacket = null,
                                    Header       = "UDP data",
                                });
                            });

                            if (sender.Send(bytes, bytes.Length, RemoteHost, RemotePort) != bytes.Length)
                            {
                                throw new Exception("UDP send failed");
                            }
                        }

                        // Listen for more bytes
                        m_listener.BeginReceive(requestCallback, null);
                    }
                    catch (Exception ex)
                    {
                        // Terminate the port on failure
                        m_failureSource.TrySetException(ex);
                    }
                }

                // Perform the first listen
                m_listener.BeginReceive(requestCallback, null);
            }
            catch (Exception ex)
            {
                // Terminate the port on failure
                m_failureSource.TrySetException(ex);
            }

            try
            {
                // Wait until failure or termination
                await m_failureSource.Task;
            }
            catch { }
        }
Ejemplo n.º 4
0
        private void ForwardStreamNew(Stream source, Stream destination, byte[] buffer, CommPacketDirection direction)
        {
            var rawVerbs = new string[] { "GET", "HEAD", "POST", "PUT", "DELETE", "TRACE", "CONNECT" };

            byte[][] verbs = rawVerbs.Select(cur => Encoding.UTF8.GetBytes(cur).Take(2).ToArray()).ToArray();
            Regex    requestLinePattern   = new Regex($"^({string.Join("|", rawVerbs)}) [^ ]+ HTTP/1.1$");
            Regex    contentLengthPattern = new Regex($"^Content-Length: ([0-9]+)$");
            Regex    chunkedPattern       = new Regex($"^Transfer-Encoding: chunked$");
            Regex    statusLinePattern    = new Regex($"^HTTP/1.1 ([0-9]+) (.*)$");
            Regex    websocketPlanet      = new Regex("GET /([0-9]+)/websocket/game HTTP/1.1");
            Regex    udpPortPattern       = new Regex("\"udpPort\"\\:([0-9]+)\\,");

            try
            {
                destination = new BufferedStream(destination);
            }
            catch (Exception ex)
            {
                Log.Error(ex, "Error creating buffered stream");
                return;
            }

            new Thread(() =>
            {
                MemoryStream ms = null;

                try
                {
                    bool isWebSocket = false;

                    while (true)
                    {
                        try
                        {
                            destination.Flush();
                        }
                        catch (Exception ex)
                        {
                            Log.Error(ex, "Error Flushing stream");
                            Kill(direction == CommPacketDirection.ServerToClient);
                        }

                        if (!m_connectionInstance.IsConnectionOpen)
                        {
                            break;
                        }

                        //if (ms != null)
                        //{
                        //    ms.Position = 0;
                        //    messagecache[direction].Enqueue(ms);
                        //}

                        //while (messagecache[direction].Count > 10)
                        //{
                        //    messagecache[direction].Dequeue();
                        //}

                        ms = new MemoryStream();
                        StreamWriter sw = null;

                        bool ReadBytes(int count)
                        {
                            int offset = 0;

                            while (offset < count)
                            {
                                int bytesRead = 0;

                                try
                                {
                                    bytesRead = source.Read(buffer, offset, count - offset);
                                }
                                catch (Exception ex)
                                {
                                    Log.Error(ex, "Error Reading stream");
                                    Kill(direction == CommPacketDirection.ClientToServer);
                                }

                                if (bytesRead == 0)
                                {
                                    return(false);
                                }

                                offset += bytesRead;
                            }

                            return(true);
                        }

                        string ReadLine()
                        {
                            List <byte> result = new List <byte>();

                            byte?prevByte = null;

                            while (true)
                            {
                                byte[] readBuffer = new byte[1];
                                if (source.Read(readBuffer, 0, 1) != 1)
                                {
                                    return(null);
                                }

                                result.Add(readBuffer[0]);

                                if (prevByte == '\r' && readBuffer[0] == '\n')
                                {
                                    break;
                                }

                                prevByte = readBuffer[0];
                            }

                            return(Encoding.UTF8.GetString(result.ToArray()).TrimEnd('\r', '\n'));
                        }

                        void DoHttpHeadersContentAndForward()
                        {
                            List <string> headers = new List <string>();

                            ulong contentLength = 0;
                            bool chunked        = false;

                            string curLine = null;
                            while ((curLine = ReadLine()) != null && curLine != string.Empty)
                            {
                                sw.WriteLine(curLine);

                                curLine = curLine.Trim();

                                Match m = contentLengthPattern.Match(curLine);
                                if (m.Success)
                                {
                                    contentLength = Convert.ToUInt64(m.Groups[1].Value);
                                }

                                m = chunkedPattern.Match(curLine);
                                if (m.Success)
                                {
                                    chunked = true;
                                }

                                headers.Add(curLine.ToLower());
                            }

                            sw.WriteLine();
                            sw.Flush();

                            if (curLine == null)
                            {
                                throw new Exception("HTTP unexpected end of stream while reading headers");
                            }

                            if (chunked && contentLength > 0)
                            {
                                throw new Exception("Chunked content with length not supported");
                            }

                            void DoReadLength(ulong curLength)
                            {
                                while (curLength > 0)
                                {
                                    int bytesRead = 0;

                                    try
                                    {
                                        bytesRead = source.Read(buffer, 0, Math.Min(buffer.Length, (int)Math.Min(int.MaxValue, curLength)));
                                    }
                                    catch (Exception ex)
                                    {
                                        Log.Error(ex, "Error reading bytes");
                                        Kill(direction == CommPacketDirection.ClientToServer);
                                    }

                                    if (bytesRead == 0)
                                    {
                                        throw new Exception("HTTP unexpected end of stream while reading content");
                                    }

                                    ms.Write(buffer, 0, bytesRead);
                                    curLength -= (ulong)bytesRead;
                                }
                            }

                            DoReadLength(contentLength);

                            if (chunked)
                            {
                                bool lastChunk = false;

                                while (!lastChunk && (curLine = ReadLine()) != null && curLine != string.Empty)
                                {
                                    sw.WriteLine(curLine);
                                    sw.Flush();

                                    var length = ulong.Parse(curLine.Trim());

                                    if (length > 0)
                                    {
                                        DoReadLength(length);
                                    }
                                    else
                                    {
                                        lastChunk = true;
                                    }

                                    curLine = ReadLine();

                                    if (curLine == null || curLine.Length != 0)
                                    {
                                        throw new Exception("HTTP protocol failure");
                                    }

                                    sw.WriteLine();
                                    sw.Flush();
                                }
                            }

                            ms.Position = 0;
                            if (!headers.Contains("content-type: application/json".ToLower()))
                            {
                                DestinationWrite(destination, ms.ToArray(), (int)ms.Length, direction);
                            }
                            else
                            {
                                var orgLength        = ms.Length;
                                string entireMessage = new StreamReader(ms).ReadToEnd();
                                ForwardHttpData(destination, entireMessage, direction);
                            }
                        }

                        void forwardWebsocketFrame()
                        {
                            WsFrame frame = null;

                            try
                            {
                                frame = new WsFrame(buffer, 2, source);
                            }
                            catch (Exception ex) {
                                Log.Error(ex, "Error creating WsFrame");
                            }

                            var worldData = frame?.Messages.FirstOrDefault(cur => cur.ApiId.HasValue && cur.ApiId.Value == 0);

                            if (worldData != null)
                            {
                                string theJson = Encoding.UTF8.GetString(worldData.Buffer, 0, worldData.Buffer.Length);

                                Match m = udpPortPattern.Match(theJson);

                                if (m.Success && planetStringName != null)
                                {
                                    int serverPort = Convert.ToInt32(m.Groups[1].Value);

                                    if (serverPort.ToString().Length != 4)
                                    {
                                        throw new Exception("Length change of udpPort");
                                    }

                                    if (!planetPorts.ContainsKey(planetStringName))
                                    {
                                        //throw new Exception($"Planet dictionary does not contain {planetStringName}");
                                    }
                                    else
                                    {
                                        planetPorts[planetStringName].RemotePort = serverPort;
                                        theJson = udpPortPattern.Replace(theJson, $"\"udpPort\":{planetPorts[planetStringName].LocalPort},");

                                        byte[] sendData = Encoding.UTF8.GetBytes(theJson);

                                        if (sendData.Length != worldData.Buffer.Length)
                                        {
                                            throw new Exception("JSON length error");
                                        }

                                        worldData.Buffer = sendData;
                                    }
                                }
                            }

                            if (planetStringName != null)
                            {
                                frame?.Messages.AddRange(GetOutgoingMessages(planetStringName, direction));
                            }

                            try
                            {
                                frame?.Send(destination);
                            }
                            catch (Exception ex)
                            {
                                Log.Error(ex, "Error sending frame");
                                Kill(direction == CommPacketDirection.ServerToClient);
                            }

                            //if (frame.readStream.Length != frame.writeStream.Length)
                            //{
                            //    throw new Exception("frame length mismatch.");
                            //}

                            //if (!frame.readStream.ToArray().SequenceEqual(frame.writeStream.ToArray()))
                            //{
                            //    throw new Exception("frame data mismatch.");
                            //}

                            if (frame == null)
                            {
                                frame = new WsFrame()
                                {
                                    Messages = new List <WsMessage>
                                    {
                                        new WsMessage(24, null, Encoding.UTF8.GetBytes("Frame decoding failure!")),
                                    },
                                };
                            }

                            try
                            {
                                websocketDataQueue[direction].Add(frame);
                            }
                            catch (Exception ex) {
                                Log.Error(ex, "Error adding frame to queue");
                            }

                            Application.Current.Dispatcher.Invoke(() =>
                            {
                                ProxyUiWindow.AddFrame(frame, direction, m_connectionInstance);
                            });
                        }

                        if (!ReadBytes(2))
                        {
                            // Connection terminated waiting for new message. This is fine.
                            break;
                        }

                        if (direction == CommPacketDirection.ClientToServer)
                        {
                            if (!verbs.Any(cur => cur[0] == buffer[0] && cur[1] == buffer[1]) && !isWebSocket)
                            {
                                isWebSocket = true;
                                ProxyManagerWindow.Instance.Dispatcher.BeginInvoke(new Action(() =>
                                {
                                    m_connectionInstance.Parent.Instances.Remove(m_connectionInstance);

                                    var wsg = ComponentEngine.Instance.GetComponent <TcpComponent>().websocketGroup;
                                    m_connectionInstance.Parent = wsg;
                                    wsg.Instances.Add(m_connectionInstance);
                                }));
                            }

                            if (!isWebSocket)
                            {
                                // GET /index.html HTTP/1.1
                                sw = new StreamWriter(ms);

                                string requestLine = (Encoding.UTF8.GetString(buffer, 0, 2) + ReadLine()).Trim();
                                sw.WriteLine(requestLine);

                                if (!requestLinePattern.IsMatch(requestLine))
                                {
                                    throw new Exception("HTTP request line invalid");
                                }

                                Match m = websocketPlanet.Match(requestLine);
                                if (m.Success)
                                {
                                    var newVal = Convert.ToInt32(m.Groups[1].Value);

                                    if (planetId != -1)
                                    {
                                        if (planetId != newVal)
                                        {
                                            throw new Exception("Multiple planets detected on a single stream");
                                        }
                                    }
                                    else
                                    {
                                        planetId          = newVal;
                                        planetStringName  = planetLookup.Where(cur => cur.Value.Value == newVal).FirstOrDefault().Key;
                                        planetDisplayName = planetLookup[planetStringName].Key;
                                    }
                                }

                                DoHttpHeadersContentAndForward();
                            }
                            else
                            {
                                forwardWebsocketFrame();
                            }
                        }
                        else
                        {
                            if ((buffer[0] != 'H' || buffer[1] != 'T') && !isWebSocket)
                            {
                                isWebSocket = true;
                                ProxyManagerWindow.Instance.Dispatcher.BeginInvoke(new Action(() =>
                                {
                                    m_connectionInstance.Parent.Instances.Remove(m_connectionInstance);

                                    var wsg = ComponentEngine.Instance.GetComponent <TcpComponent>().websocketGroup;
                                    m_connectionInstance.Parent = wsg;
                                    wsg.Instances.Add(m_connectionInstance);
                                }));
                            }

                            if (!isWebSocket)
                            {
                                // HTTP/1.1 200 OK
                                sw = new StreamWriter(ms);

                                string statusLine = (Encoding.UTF8.GetString(buffer, 0, 2) + ReadLine()).Trim();

                                sw.WriteLine(statusLine);

                                if (!statusLinePattern.IsMatch(statusLine))
                                {
                                    throw new Exception("HTTP status line invalid");
                                }

                                DoHttpHeadersContentAndForward();
                            }
                            else
                            {
                                forwardWebsocketFrame();
                            }
                        }
                    }

                    Log.Information("Killing connection");
                    Kill(direction == CommPacketDirection.ClientToServer);
                }
                catch (Exception ex)
                {
                    Log.Error(ex, "Forward Stream error");
                    Kill(direction == CommPacketDirection.ClientToServer);
                }
            }).Start();
        }