protected void SBParseMSG(PacketStream stream, TransactionNode payloadNode, int payloadLength) { List <PacketSlice> slices = new List <PacketSlice>(2); string content = stream.PeekStringUTF8(payloadLength); TransactionNode headersNode = new TransactionNode(payloadNode, "Headers"); int pos = content.IndexOf("\r\n\r\n"); string headers = content.Substring(0, pos); string[] lines = headers.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); foreach (string line in lines) { stream.ReadBytes(StaticUtils.GetUTF8ByteCount(line), slices); string[] tokens = line.Split(new char[] { ':' }, 2); tokens[1] = tokens[1].TrimStart(new char[] { ' ' }); headersNode.AddField(tokens[0], tokens[1], "Message header field.", slices); // Skip CRLF stream.ReadBytes(2); } // Skip extra CRLF stream.ReadBytes(2); int bodyLength = payloadLength - StaticUtils.GetUTF8ByteCount(headers) - 4; if (bodyLength > 0) { TransactionNode bodyNode = new TransactionNode(payloadNode, "Body"); string contentType = (string)headersNode.Fields["Content-Type"]; contentType = contentType.Split(new char[] { ';' }, 2)[0]; if (contentType == "application/x-msnmsgrp2p") { ReadNextP2PMessageChunk(stream, bodyNode); UInt32 appID = stream.ReadU32BE(slices); bodyNode.AddField("AppID", appID, "Application ID.", slices); } else if (contentType == "text/x-msmsgsinvite") { string bodyStr = stream.ReadStringUTF8(bodyLength, slices); bodyNode.AddTextField("Body", bodyStr, "Invite body.", slices); } else { string bodyStr = stream.ReadStringUTF8(bodyLength, slices); bodyNode.AddField("Body", bodyStr, "Body.", slices); } } }
protected void AddBodyNode(PacketStream stream, TransactionNode transactionNode, string contentType, string contentEncoding, int bodyLen) { List <PacketSlice> slices = new List <PacketSlice>(1); TransactionNode bodyNode = new TransactionNode("Body"); byte[] body = stream.ReadBytes(bodyLen, slices); if (contentType == "text/html" || contentType == "text/xml") { int realBodyLen = body.Length; if (body[realBodyLen - 1] == '\0') { realBodyLen--; } Decoder dec; if (contentEncoding == "utf-8") { dec = Encoding.UTF8.GetDecoder(); } else { dec = Encoding.ASCII.GetDecoder(); } char[] bodyChars = new char[dec.GetCharCount(body, 0, realBodyLen)]; dec.GetChars(body, 0, realBodyLen, bodyChars, 0); string bodyStr = new string(bodyChars); if (contentType == "text/xml") { bodyNode.AddXMLField("XML", bodyStr, "Body XML data.", slices); } else { bodyNode.AddTextField("HTML", bodyStr, "Body HTML data.", slices); } } else if (contentType == "application/vnd.ms-sync.wbxml") { string xml = WBXML.ConvertToXML(body); bodyNode.AddXMLField("WBXML", xml, "Body WBXML data.", slices); } else { bodyNode.AddField("Raw", body, StaticUtils.FormatByteArray(body), "Raw body data.", slices); } transactionNode.AddChild(bodyNode); }
private bool HandleSwitchboardSession(IPSession session) { List<PacketSlice> slices = new List<PacketSlice>(1); logger.AddMessage(String.Format("\r\n\r\nparsing session with remote endpoint: {0}\r\n", session.RemoteEndpoint)); while (true) { PacketStream stream = session.GetNextStreamDirection(); if (stream.GetBytesAvailable() == 0) { stream = session.GetNextStreamDirection(); if (stream.GetBytesAvailable() == 0) { break; } } IPPacket pkt = stream.CurPacket; PacketDirection direction = pkt.Direction; try { string line = stream.PeekLineUTF8(); // Split the line up into CMD and the rest (being arguments, if any) string[] tokens = line.Split(new char[] { ' ' }, 2); logger.AddMessage(String.Format("{0} parsing command '{1}' (line: {2})", (direction == PacketDirection.PACKET_DIRECTION_INCOMING) ? "<<" : ">>", tokens[0], line)); // Set cmd and create an array of arguments if present string cmd = tokens[0]; string[] arguments = new string[0]; if (tokens.Length > 1) { arguments = tokens[1].Split(new char[] { ' ' }); } // Create command node TransactionNode node = new TransactionNode("MSNSBCommand"); node.Description = cmd; // Command field stream.ReadBytes(StaticUtils.GetUTF8ByteCount(tokens[0]), slices); node.AddField("Command", tokens[0], "Switchboard command.", slices); if (arguments.Length > 0) { // Skip space between command and arguments stream.ReadByte(); stream.ReadBytes(StaticUtils.GetUTF8ByteCount(tokens[1]), slices); // Arguments fields node.AddField("Arguments", tokens[1], "Arguments to command.", slices); } // Skip CRLF stream.ReadBytes(2); // Is there a payload? bool hasPayload = false; if (arguments.Length > 0) { List<string> payloadCommands = (direction == PacketDirection.PACKET_DIRECTION_OUTGOING) ? payloadCommandsFromClient : payloadCommandsFromServer; hasPayload = payloadCommands.Contains(cmd); } if (hasPayload) { int payloadLength = -1; try { payloadLength = (int)Convert.ToUInt32(arguments[arguments.Length - 1]); } catch (FormatException) { } if (payloadLength > 0) { TransactionNode payloadNode = new TransactionNode(node, "Payload"); logger.AddMessage(String.Format("Parsing {0} bytes of payload", payloadLength)); PayloadFormat format = PayloadFormat.TEXT; string cmdUpper = cmd.ToUpper(); if (payloadCommandFormats.ContainsKey(cmdUpper)) format = payloadCommandFormats[cmdUpper]; if (format == PayloadFormat.MESSAGE) { SBParseMSG(stream, payloadNode, payloadLength); } else { string body = stream.ReadStringUTF8(payloadLength, slices); switch (format) { case PayloadFormat.SLP: payloadNode.AddTextField("MSNSLP", body, "MSNSLP data.", slices); break; case PayloadFormat.XML: payloadNode.AddXMLField("XML", body, "XML data.", slices); break; default: payloadNode.AddTextField("Text", body, "Text.", slices); break; } } } } session.AddNode(node); } catch (EndOfStreamException e) { logger.AddMessage(String.Format("MSNSwitchboard: EOS at {0} ({1})", stream.Position, e)); break; } } logger.AddMessage("done with session\r\n\r\n"); return true; }
protected void SBParseMSG(PacketStream stream, TransactionNode payloadNode, int payloadLength) { List<PacketSlice> slices = new List<PacketSlice>(2); string content = stream.PeekStringUTF8(payloadLength); TransactionNode headersNode = new TransactionNode(payloadNode, "Headers"); int pos = content.IndexOf("\r\n\r\n"); string headers = content.Substring(0, pos); string[] lines = headers.Split(new string[] { "\r\n" }, StringSplitOptions.RemoveEmptyEntries); foreach (string line in lines) { stream.ReadBytes(StaticUtils.GetUTF8ByteCount(line), slices); string[] tokens = line.Split(new char[] { ':' }, 2); tokens[1] = tokens[1].TrimStart(new char[] { ' ' }); headersNode.AddField(tokens[0], tokens[1], "Message header field.", slices); // Skip CRLF stream.ReadBytes(2); } // Skip extra CRLF stream.ReadBytes(2); int bodyLength = payloadLength - StaticUtils.GetUTF8ByteCount(headers) - 4; if (bodyLength > 0) { TransactionNode bodyNode = new TransactionNode(payloadNode, "Body"); string contentType = (string)headersNode.Fields["Content-Type"]; contentType = contentType.Split(new char[] { ';' }, 2)[0]; if (contentType == "application/x-msnmsgrp2p") { ReadNextP2PMessageChunk(stream, bodyNode); UInt32 appID = stream.ReadU32BE(slices); bodyNode.AddField("AppID", appID, "Application ID.", slices); } else if (contentType == "text/x-msmsgsinvite") { string bodyStr = stream.ReadStringUTF8(bodyLength, slices); bodyNode.AddTextField("Body", bodyStr, "Invite body.", slices); } else { string bodyStr = stream.ReadStringUTF8(bodyLength, slices); bodyNode.AddField("Body", bodyStr, "Body.", slices); } } }
protected void ReadNextP2PMessageChunk(PacketStream stream, TransactionNode parentNode) { TransactionNode p2pNode = new TransactionNode(parentNode, "MSNP2PMessageChunk"); // Headers TransactionNode p2pHeaders = new TransactionNode(p2pNode, "Headers"); List<PacketSlice> slices = new List<PacketSlice>(); UInt32 sessionID = stream.ReadU32LE(slices); p2pHeaders.AddField("SessionID", sessionID, "Session ID.", slices); UInt32 messageID = stream.ReadU32LE(slices); p2pHeaders.AddField("MessageID", messageID, "Message ID.", slices); UInt64 dataOffset = stream.ReadU64LE(slices); p2pHeaders.AddField("DataOffset", dataOffset, "Data offset.", slices); UInt64 dataSize = stream.ReadU64LE(slices); p2pHeaders.AddField("DataSize", dataSize, "Data size.", slices); UInt32 chunkSize = stream.ReadU32LE(slices); p2pHeaders.AddField("ChunkSize", chunkSize, "Chunk size.", slices); UInt32 flags = stream.ReadU32LE(slices); p2pHeaders.AddField("Flags", flags, StaticUtils.FormatFlags(flags), "Flags.", slices); UInt32 ackedMsgID = stream.ReadU32LE(slices); p2pHeaders.AddField("AckedMsgID", ackedMsgID, "MessageID of the message to be acknowledged.", slices); UInt32 prevAckedMsgID = stream.ReadU32LE(slices); p2pHeaders.AddField("PrevAckedMsgID", prevAckedMsgID, "AckedMsgID of the last chunk to ack.", slices); UInt64 ackedDataSize = stream.ReadU64LE(slices); p2pHeaders.AddField("AckedDataSize", ackedDataSize, "Acknowledged data size.", slices); // Body TransactionNode p2pContent = null; if (chunkSize > 0) { p2pContent = new TransactionNode(p2pNode, "Content"); byte[] bytes = stream.ReadBytes((int)chunkSize, slices); if (sessionID != 0) { p2pContent.AddField("Raw", bytes, StaticUtils.FormatByteArray(bytes), "Raw content.", slices); } else { p2pContent.AddTextField("MSNSLP", bytes, StaticUtils.DecodeUTF8(bytes), "MSNSLP data.", slices); } } }
protected void ReadNextP2PMessageChunk(PacketStream stream, TransactionNode parentNode) { TransactionNode p2pNode = new TransactionNode(parentNode, "MSNP2PMessageChunk"); // Headers TransactionNode p2pHeaders = new TransactionNode(p2pNode, "Headers"); List <PacketSlice> slices = new List <PacketSlice>(); UInt32 sessionID = stream.ReadU32LE(slices); p2pHeaders.AddField("SessionID", sessionID, "Session ID.", slices); UInt32 messageID = stream.ReadU32LE(slices); p2pHeaders.AddField("MessageID", messageID, "Message ID.", slices); UInt64 dataOffset = stream.ReadU64LE(slices); p2pHeaders.AddField("DataOffset", dataOffset, "Data offset.", slices); UInt64 dataSize = stream.ReadU64LE(slices); p2pHeaders.AddField("DataSize", dataSize, "Data size.", slices); UInt32 chunkSize = stream.ReadU32LE(slices); p2pHeaders.AddField("ChunkSize", chunkSize, "Chunk size.", slices); UInt32 flags = stream.ReadU32LE(slices); p2pHeaders.AddField("Flags", flags, StaticUtils.FormatFlags(flags), "Flags.", slices); UInt32 ackedMsgID = stream.ReadU32LE(slices); p2pHeaders.AddField("AckedMsgID", ackedMsgID, "MessageID of the message to be acknowledged.", slices); UInt32 prevAckedMsgID = stream.ReadU32LE(slices); p2pHeaders.AddField("PrevAckedMsgID", prevAckedMsgID, "AckedMsgID of the last chunk to ack.", slices); UInt64 ackedDataSize = stream.ReadU64LE(slices); p2pHeaders.AddField("AckedDataSize", ackedDataSize, "Acknowledged data size.", slices); // Body TransactionNode p2pContent = null; if (chunkSize > 0) { p2pContent = new TransactionNode(p2pNode, "Content"); byte[] bytes = stream.ReadBytes((int)chunkSize, slices); if (sessionID != 0) { p2pContent.AddField("Raw", bytes, StaticUtils.FormatByteArray(bytes), "Raw content.", slices); } else { p2pContent.AddTextField("MSNSLP", bytes, StaticUtils.DecodeUTF8(bytes), "MSNSLP data.", slices); } } }
private bool HandleSwitchboardSession(IPSession session) { List <PacketSlice> slices = new List <PacketSlice>(1); logger.AddMessage(String.Format("\r\n\r\nparsing session with remote endpoint: {0}\r\n", session.RemoteEndpoint)); while (true) { PacketStream stream = session.GetNextStreamDirection(); if (stream.GetBytesAvailable() == 0) { stream = session.GetNextStreamDirection(); if (stream.GetBytesAvailable() == 0) { break; } } IPPacket pkt = stream.CurPacket; PacketDirection direction = pkt.Direction; try { string line = stream.PeekLineUTF8(); // Split the line up into CMD and the rest (being arguments, if any) string[] tokens = line.Split(new char[] { ' ' }, 2); logger.AddMessage(String.Format("{0} parsing command '{1}' (line: {2})", (direction == PacketDirection.PACKET_DIRECTION_INCOMING) ? "<<" : ">>", tokens[0], line)); // Set cmd and create an array of arguments if present string cmd = tokens[0]; string[] arguments = new string[0]; if (tokens.Length > 1) { arguments = tokens[1].Split(new char[] { ' ' }); } // Create command node TransactionNode node = new TransactionNode("MSNSBCommand"); node.Description = cmd; // Command field stream.ReadBytes(StaticUtils.GetUTF8ByteCount(tokens[0]), slices); node.AddField("Command", tokens[0], "Switchboard command.", slices); if (arguments.Length > 0) { // Skip space between command and arguments stream.ReadByte(); stream.ReadBytes(StaticUtils.GetUTF8ByteCount(tokens[1]), slices); // Arguments fields node.AddField("Arguments", tokens[1], "Arguments to command.", slices); } // Skip CRLF stream.ReadBytes(2); // Is there a payload? bool hasPayload = false; if (arguments.Length > 0) { List <string> payloadCommands = (direction == PacketDirection.PACKET_DIRECTION_OUTGOING) ? payloadCommandsFromClient : payloadCommandsFromServer; hasPayload = payloadCommands.Contains(cmd); } if (hasPayload) { int payloadLength = -1; try { payloadLength = (int)Convert.ToUInt32(arguments[arguments.Length - 1]); } catch (FormatException) { } if (payloadLength > 0) { TransactionNode payloadNode = new TransactionNode(node, "Payload"); logger.AddMessage(String.Format("Parsing {0} bytes of payload", payloadLength)); PayloadFormat format = PayloadFormat.TEXT; string cmdUpper = cmd.ToUpper(); if (payloadCommandFormats.ContainsKey(cmdUpper)) { format = payloadCommandFormats[cmdUpper]; } if (format == PayloadFormat.MESSAGE) { SBParseMSG(stream, payloadNode, payloadLength); } else { string body = stream.ReadStringUTF8(payloadLength, slices); switch (format) { case PayloadFormat.SLP: payloadNode.AddTextField("MSNSLP", body, "MSNSLP data.", slices); break; case PayloadFormat.XML: payloadNode.AddXMLField("XML", body, "XML data.", slices); break; default: payloadNode.AddTextField("Text", body, "Text.", slices); break; } } } } session.AddNode(node); } catch (EndOfStreamException e) { logger.AddMessage(String.Format("MSNSwitchboard: EOS at {0} ({1})", stream.Position, e)); break; } } logger.AddMessage("done with session\r\n\r\n"); return(true); }
protected void AddBodyNode(PacketStream stream, TransactionNode transactionNode, string contentType, string contentEncoding, int bodyLen) { List<PacketSlice> slices = new List<PacketSlice>(1); TransactionNode bodyNode = new TransactionNode("Body"); byte[] body = stream.ReadBytes(bodyLen, slices); if (contentType == "text/html" || contentType == "text/xml") { int realBodyLen = body.Length; if (body[realBodyLen - 1] == '\0') realBodyLen--; Decoder dec; if (contentEncoding == "utf-8") { dec = Encoding.UTF8.GetDecoder(); } else { dec = Encoding.ASCII.GetDecoder(); } char[] bodyChars = new char[dec.GetCharCount(body, 0, realBodyLen)]; dec.GetChars(body, 0, realBodyLen, bodyChars, 0); string bodyStr = new string(bodyChars); if (contentType == "text/xml") bodyNode.AddXMLField("XML", bodyStr, "Body XML data.", slices); else bodyNode.AddTextField("HTML", bodyStr, "Body HTML data.", slices); } else if (contentType == "application/vnd.ms-sync.wbxml") { string xml = WBXML.ConvertToXML(body); bodyNode.AddXMLField("WBXML", xml, "Body WBXML data.", slices); } else { bodyNode.AddField("Raw", body, StaticUtils.FormatByteArray(body), "Raw body data.", slices); } transactionNode.AddChild(bodyNode); }