private void SendBytesToUi(byte[] saveData, CommPacketDirection direction) { var length = saveData.Search(saveData.Length, new byte[] { 13, 10 }); var dataStringSegments = Encoding.UTF8.GetString(saveData, 0, length).Split(' '); string header = "HTTP Data"; if (dataStringSegments[2].StartsWith("HTTP")) { header = $"{dataStringSegments[0]} {dataStringSegments[1]}"; } else if (dataStringSegments[0].StartsWith("HTTP")) { var desc = dataStringSegments[2]; for (int i = 3; i < dataStringSegments.Length; ++i) { desc += $" {dataStringSegments[i]}"; } header = $"{dataStringSegments[1]} {desc}"; } ProxyUiWindow.Instance.GetDataContext <ProxyUiWindowViewModel>().SendBytesToUi(m_connectionInstance, new CommPacket { Data = saveData, Direction = direction, Id = Guid.NewGuid(), Instance = m_connectionInstance, ParentPacket = null, Header = header, }); }
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 Forward(Stream source, Stream destination, IAsyncResult asyncResult, byte[] buffer) { try { CommPacketDirection direction = (CommPacketDirection)asyncResult.AsyncState; var bytesRead = source.EndRead(asyncResult); if (bytesRead == 0) { Kill(); return; } if (ReplaceIpaddr && buffer.Search(bytesRead, ipAddrBytes) > 0) { string request = Encoding.UTF8.GetString(buffer, 0, bytesRead); Regex ipSubPattern = new Regex("\\,\"ipAddr\":\"[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\"\\,"); Match ipSubMatch = ipSubPattern.Match(request); if (ipSubMatch.Success) { string org = ipSubMatch.Groups[0].Value; string rep = ",\"ipAddr\":\"127.0.0.1\","; Regex reg = new Regex("Content-Length\\: ([0-9]*)"); Match m = reg.Match(request); if (!m.Success) { } int length = Convert.ToInt32(m.Groups[1].Value); int newLength = length + rep.Length - org.Length; request = request.Replace(org, rep); request = request.Replace($"Content-Length: {length}", $"Content-Length: {newLength}"); byte[] sendBytes = Encoding.UTF8.GetBytes(request); DestinationWrite(destination, sendBytes, sendBytes.Length, direction); } else { DestinationWrite(destination, buffer, bytesRead, direction); } } else { DestinationWrite(destination, buffer, bytesRead, direction); } ForwardStream(source, destination, buffer, direction); } catch { Kill(); } }
private void ForwardStream(Stream source, Stream destination, byte[] buffer, CommPacketDirection direction) { try { source.BeginRead(buffer, 0, buffer.Length, r => Forward(source, destination, r, buffer), direction); } catch { Kill(); } }
private void DestinationWrite(Stream destination, byte[] buffer, int count, CommPacketDirection direction) { if (ProxyUiWindow.Instance.GetDataContext <ProxyUiWindowViewModel>().CaptureEnabled) { byte[] saveData = new byte[count]; Buffer.BlockCopy(buffer, 0, saveData, 0, count); SendBytesToUi(saveData, direction); } TryWriteStream(destination, buffer, 0, count, direction == CommPacketDirection.ServerToClient); }
public static void AddFrame(WsFrame frame, CommPacketDirection direction, ConnectionInstance connectionInstance) { if (instance == null || !instance.Data.CaptureEnabled) { return; } try { var parentPacket = new CommPacket { Data = frame.HeaderBytes, Direction = direction, Id = Guid.NewGuid(), Instance = connectionInstance, ParentPacket = null, Header = "Websocket Frame", }; foreach (var curMessage in frame.Messages) { var headerPacket = new CommPacket { Data = BitConverter.GetBytes((ushort)(curMessage.Buffer.Length + 1)).Concat(new byte[] { curMessage.ApiId ?? 0 }).ToArray(), Direction = direction, Id = Guid.NewGuid(), Instance = connectionInstance, ParentPacket = parentPacket, Header = $"Websocket Message[0x{curMessage.ApiId ?? 0:X2}]", }; var payloadPacket = new CommPacket { Data = curMessage.Buffer, Direction = direction, Id = Guid.NewGuid(), Instance = connectionInstance, ParentPacket = parentPacket, Header = $"Websocket Payload", }; headerPacket.ChildPackets.Add(payloadPacket); parentPacket.ChildPackets.Add(headerPacket); } ; instance.Data.SendBytesToUi(connectionInstance, parentPacket); } catch (Exception ex) { Log.Error(ex, "Error in AddFrame"); } }
public static void AddOutgoingMessage(string planet, CommPacketDirection direction, WsMessage message) { var outgoingQueue = OutgoingQueueDirection[direction]; if (!outgoingQueue.TryGetValue(planet, out var collection)) { collection = new BlockingCollection <WsMessage>(); if (!outgoingQueue.TryAdd(planet, collection)) { collection = outgoingQueue[planet]; } } collection.Add(message); }
public static void WriteBytes(byte[] buffer, int count, CommPacketDirection direction, ConnectionInstance connectionInstance) { if (instance == null || !instance.Data.CaptureEnabled) { return; } try { byte[] saveData = new byte[count]; Buffer.BlockCopy(buffer, 0, saveData, 0, count); var length = saveData.Search(saveData.Length, new byte[] { 13, 10 }); var dataStringSegments = Encoding.UTF8.GetString(saveData, 0, length).Split(' '); string header = "HTTP Data"; if (dataStringSegments[2].StartsWith("HTTP")) { header = $"{dataStringSegments[0]} {dataStringSegments[1]}"; } else if (dataStringSegments[0].StartsWith("HTTP")) { var desc = dataStringSegments[2]; for (int i = 3; i < dataStringSegments.Length; ++i) { desc += $" {dataStringSegments[i]}"; } header = $"{dataStringSegments[1]} {desc}"; } instance.Data.SendBytesToUi(connectionInstance, new CommPacket { Data = saveData, Direction = direction, Id = Guid.NewGuid(), Instance = connectionInstance, ParentPacket = null, Header = header, }); } catch (Exception ex) { Log.Error(ex, "Error in WriteBytes"); } }
private static List <WsMessage> GetOutgoingMessages(string planet, CommPacketDirection direction) { var outgoingQueue = OutgoingQueueDirection[direction]; List <WsMessage> result = new List <WsMessage>(); if (outgoingQueue.TryGetValue(planet, out var collection)) { while (collection.TryTake(out var curItem)) { result.Add(curItem); } } return(result); }
private void Dispatcher(CommPacketDirection direction) { new Thread(() => { try { var myQueue = websocketDataQueue[direction]; OnFrameHandler myHandler() { return(direction == CommPacketDirection.ClientToServer ? onFrameOut : onFrameIn); } while (true) { WsFrame curFrame; try { curFrame = myQueue.Take(); } catch { break; } var curHandler = myHandler(); if (curHandler != null) { foreach (OnFrameHandler curInvoke in curHandler.GetInvocationList()) { try { curInvoke(planetId, planetDisplayName ?? string.Empty, curFrame); } catch { } } } } } catch { } }).Start(); }
private void DestinationWrite(Stream destination, byte[] buffer, int count, CommPacketDirection direction) { if (m_connectionInstance.Parent.Model.CaptureEnabled) { byte[] saveData = buffer.Take(count).ToArray(); MainWindow.Instance.Dispatcher.BeginInvoke(new Action(() => { var packet = new CommPacket { Data = saveData, Direction = direction, HostName = m_connectionInstance.HostName, Id = Guid.NewGuid(), Parent = m_connectionInstance, }; m_connectionInstance.Packets.Add(packet); while (m_connectionInstance.Packets.Count > 1000) { var curPacket = m_connectionInstance.Packets[0]; m_connectionInstance.Packets.RemoveAt(0); curPacket.Searches.ToList().ForEach(cur => cur.Packets.Remove(curPacket)); } foreach (var curSearch in m_connectionInstance.Parent.Model.Searches) { if (saveData.Search(count, curSearch.searchBytes) > -1) { packet.Searches.Add(curSearch); curSearch.Packets.Add(packet); } } })); } destination.Write(buffer, 0, count); }
private void DestinationWrite(Stream destination, string entireMessage, CommPacketDirection direction) { byte[] sendBytes = Encoding.UTF8.GetBytes(entireMessage); DestinationWrite(destination, sendBytes, sendBytes.Length, direction); }
private void ForwardHttpData(Stream destination, string entireMessage, CommPacketDirection direction) { if (planetDisplayName == null && entireMessage.Contains("\"worldData\"") && entireMessage.Contains("\"displayName\"") && entireMessage.Contains("\"id\"") && entireMessage.Contains("\"name\"")) { try { var gameserverJson = JObject.Parse(entireMessage.Substring(entireMessage.IndexOf("\r\n\r\n") + 4)); planetId = gameserverJson["worldData"]["id"].Value <int>(); planetDisplayName = gameserverJson["worldData"]["displayName"].ToString(); planetStringName = gameserverJson["worldData"]["name"].ToString(); if (!planetLookup.ContainsKey(planetStringName)) { planetLookup.Add(planetStringName, new KeyValuePair <string, int>(planetDisplayName, planetId)); } } catch { } } if (ReplaceIpaddr && entireMessage.Contains("ipAddr")) { Regex ipSubPattern = new Regex("\\,\"ipAddr\":\"(?!127\\.0\\.0\\.1)[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\"\\,"); Match ipSubMatch = ipSubPattern.Match(entireMessage); if (ipSubMatch.Success) { Regex reg = new Regex("Content-Length\\: ([0-9]+)", RegexOptions.IgnoreCase); Match m = reg.Match(entireMessage); int length = Convert.ToInt32(m.Groups[1].Value); int newLength = length; if (!m.Success) { throw new Exception("This shouldn't happen..."); } int lenBeforeReplace = entireMessage.Length; while (ipSubMatch.Success) { string org = ipSubMatch.Groups[0].Value; string rep = ",\"ipAddr\":\"127.0.0.1\","; entireMessage = entireMessage.Replace(org, rep); ipSubMatch = ipSubPattern.Match(entireMessage); } int lenAfterReplace = entireMessage.Length; newLength += lenAfterReplace - lenBeforeReplace; entireMessage = entireMessage.Replace(m.Groups[0].Value, $"Content-Length: {newLength}"); DestinationWrite(destination, entireMessage, direction); } else { DestinationWrite(destination, entireMessage, direction); } } else { DestinationWrite(destination, entireMessage, direction); } }
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(); }