/* * Copyright (c) 2006-2014, openmetaverse.org * All rights reserved. * * - Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * - Neither the name of the openmetaverse.org nor the names * of its contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ using System; using System.IO; using System.Net; using System.Linq; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Text.RegularExpressions; using System.Drawing; using System.Text; using System.Windows.Forms; using System.Reflection; using System.Threading; using GridProxy; using OpenMetaverse; using OpenMetaverse.Packets; using OpenMetaverse.StructuredData; using OpenMetaverse.Interfaces; using System.Xml; using Nwc.XmlRpc; using Logger = OpenMetaverse.Logger; namespace WinGridProxy { public partial class FormWinGridProxy : Form { // only allow one thread at a time to do file I/O operations private object m_FileIOLockerObject = new object(); // Class for saving and restoring settings private static SettingsStore Store = new SettingsStore(); private static bool m_ProxyRunning; private Assembly m_CurrentAssembly = Assembly.GetExecutingAssembly(); ProxyManager proxy; private FormPluginManager pluginManager; private int PacketCounter; // stats tracking private int CapsInCounter; private int CapsInBytes; private int CapsOutCounter; private int CapsOutBytes; private int PacketsInCounter; private int PacketsInBytes; private int PacketsOutCounter; private int PacketsOutBytes; private List QueuedSessions; private bool monoRuntime; private const string PROTO_CAPABILITIES = "Cap"; private const string PROTO_EVENTMESSAGE = "Event"; private const string PROTO_PACKETSTRING = "UDP"; private const string PROTO_AUTHENTICATE = "https"; // some default colors for session items private readonly Color Color_Login = Color.OldLace; private readonly Color Color_Packet = Color.LightYellow; private readonly Color Color_Cap = Color.Honeydew; private readonly Color Color_Event = Color.AliceBlue; public FormWinGridProxy() { InitializeComponent(); Logger.Log("WinGridProxy ready", Helpers.LogLevel.Info); if (FireEventAppender.Instance != null) { FireEventAppender.Instance.MessageLoggedEvent += new MessageLoggedEventHandler(Instance_MessageLoggedEvent); } // Attempt to work around some mono bugs monoRuntime = Type.GetType("Mono.Runtime") != null; // Officially supported way of detecting mono if (monoRuntime) { Font fixedFont = new Font(FontFamily.GenericMonospace, 9f, FontStyle.Regular, GraphicsUnit.Point); richTextBoxDecodedRequest.Font = richTextBoxDecodedResponse.Font = richTextBoxNotationRequest.Font = richTextBoxNotationResponse.Font = richTextBoxRawRequest.Font = richTextBoxRawResponse.Font = fixedFont; } QueuedSessions = new List(); // populate the listen box with the known IP Addresses of this host IPHostEntry iphostentry = Dns.GetHostByName(Dns.GetHostName()); foreach (IPAddress address in iphostentry.AddressList) comboBoxListenAddress.Items.Add(address.ToString()); ProxyManager.OnPacketLog += ProxyManager_OnPacketLog; ProxyManager.OnMessageLog += ProxyManager_OnMessageLog; ProxyManager.OnLoginResponse += ProxyManager_OnLoginResponse; ProxyManager.OnCapabilityAdded += ProxyManager_OnCapabilityAdded; ProxyManager.OnEventMessageLog += ProxyManager_OnEventMessageLog; } #region Event Handlers for Messages/Packets /// /// Adds a new EventQueue message to the Message Filters listview. /// /// /// void ProxyManager_OnEventMessageLog(CapsRequest req, CapsStage stage) { if (this.InvokeRequired) { this.BeginInvoke(new MethodInvoker(() => ProxyManager_OnEventMessageLog(req, stage))); } else { ListViewItem foundCap = FindListViewItem(listViewMessageFilters, req.Info.CapType, false); if (foundCap == null) { ListViewItem addedItem = listViewMessageFilters.Items.Add(new ListViewItem(req.Info.CapType, listViewMessageFilters.Groups["EventQueueMessages"])); addedItem.SubItems.Add(PROTO_EVENTMESSAGE); addedItem.BackColor = Color_Event; if (autoAddNewDiscoveredMessagesToolStripMenuItem.Checked) addedItem.Checked = true; } else { ProxyManager_OnMessageLog(req, CapsStage.Response); } } } /// /// Adds a new Capability message to the message filters listview /// private void ProxyManager_OnCapabilityAdded(CapInfo cap) { if (this.InvokeRequired) { this.BeginInvoke(new MethodInvoker(() => ProxyManager_OnCapabilityAdded(cap))); } else { ListViewItem foundCap = FindListViewItem(listViewMessageFilters, cap.CapType, false); if (foundCap == null) { ListViewItem addedItem = listViewMessageFilters.Items.Add(new ListViewItem(cap.CapType, listViewMessageFilters.Groups["Capabilities"])); addedItem.SubItems.Add(PROTO_CAPABILITIES); addedItem.BackColor = Color_Cap; if (autoAddNewDiscoveredMessagesToolStripMenuItem.Checked) addedItem.Checked = true; } } } /// /// Handle Login Requests/Responses /// private void ProxyManager_OnLoginResponse(object request, Direction direction) { if (this.InvokeRequired) { this.BeginInvoke(new MethodInvoker(() => ProxyManager_OnLoginResponse(request, direction))); } else { string loginType; if (request is XmlRpcRequest) { loginType = "Login Request"; } else { loginType = "Login Response"; } ListViewItem foundItem = FindListViewItem(listViewPacketFilters, loginType, false); if (foundItem != null && foundItem.Checked == true) { PacketCounter++; SessionLogin sessionLogin = new SessionLogin(request, direction, comboBoxLoginURL.Text, request.GetType().Name + " " + loginType); ListViewItem sessionEntry = new ListViewItem(new string[] { PacketCounter.ToString(), sessionLogin.TimeStamp.ToString("HH:mm:ss.fff"), sessionLogin.Protocol, sessionLogin.Name, sessionLogin.Length.ToString(), sessionLogin.Host, sessionLogin.ContentType }); sessionEntry.Tag = sessionLogin; sessionEntry.ImageIndex = (int)sessionLogin.Direction; AddSession(sessionEntry); } } } // Only raised when we've told GridProxy we want a specific packet type private void ProxyManager_OnPacketLog(Packet packet, Direction direction, IPEndPoint endpoint) { PacketCounter++; if (direction == Direction.Incoming) { PacketsInCounter++; PacketsInBytes += packet.Length; } else { PacketsOutCounter++; PacketsOutBytes += packet.Length; } SessionPacket sessionPacket = new SessionPacket(packet, direction, endpoint, PacketDecoder.InterpretOptions(packet.Header) + " Seq: " + packet.Header.Sequence.ToString() + " Freq:" + packet.Header.Frequency.ToString()); ListViewItem sessionItem = new ListViewItem(new string[] { PacketCounter.ToString(), sessionPacket.TimeStamp.ToString("HH:mm:ss.fff"), sessionPacket.Protocol, sessionPacket.Name, sessionPacket.Length.ToString(), sessionPacket.Host, sessionPacket.ContentType }); sessionItem.Tag = sessionPacket; sessionItem.ImageIndex = (int)sessionPacket.Direction; AddSession(sessionItem); } /// /// Handle Capabilities /// private void ProxyManager_OnMessageLog(CapsRequest req, CapsStage stage) { if (this.InvokeRequired) { this.BeginInvoke(new MethodInvoker(() => ProxyManager_OnMessageLog(req, stage))); } else { ListViewItem found = FindListViewItem(listViewMessageFilters, req.Info.CapType, false); if (found != null && found.Checked) { PacketCounter++; int size = 0; string contentType = String.Empty; if (req.RawRequest != null) { size += req.RawRequest.Length; contentType = req.RequestHeaders.Get("Content-Type"); //req.RequestHeaders["Content-Type"]; } if (req.RawResponse != null) { size += req.RawResponse.Length; contentType = req.ResponseHeaders.Get("Content-Type"); } Direction direction; if (stage == CapsStage.Request) { CapsOutCounter++; CapsOutBytes += req.Request.ToString().Length; direction = Direction.Outgoing; } else { CapsInCounter++; CapsInBytes += req.Response.ToString().Length; direction = Direction.Incoming; } string proto = found.SubItems[1].Text; Session capsSession = null; if (found.Group.Header.Equals("Capabilities")) { capsSession = new SessionCaps(req.RawRequest, req.RawResponse, req.RequestHeaders, req.ResponseHeaders, direction, req.Info.URI, req.Info.CapType, proto, req.FullUri); } else { capsSession = new SessionEvent(req.RawResponse, req.ResponseHeaders, req.Info.URI, req.Info.CapType, proto); } string[] s = { PacketCounter.ToString(), capsSession.TimeStamp.ToString("HH:mm:ss.fff"), capsSession.Protocol, capsSession.Name, capsSession.Length.ToString(), capsSession.Host, capsSession.ContentType }; ListViewItem session = new ListViewItem(s); session.ImageIndex = (int)direction; session.Tag = capsSession; session.BackColor = found.BackColor; AddSession(session); } else { if (found == null) { // must be a new event not in KnownCaps, lets add it to the listview ListViewItem addedItem = listViewMessageFilters.Items.Add(new ListViewItem(req.Info.CapType)); addedItem.BackColor = Color_Cap; if (autoAddNewDiscoveredMessagesToolStripMenuItem.Checked) addedItem.Checked = true; } } } } #endregion #region Helpers private ListViewItem FindListViewItem(ListView listView, string key, bool searchAll) { foreach (ListViewItem item in listView.Items) { if (item.Text.Equals(key) || (searchAll && item.SubItems.ContainsKey(key))) return item; } return null; } private static string FormatBytes(long bytes) { const int scale = 1024; string[] orders = new string[] { "GB", "MB", "KB", "Bytes" }; long max = (long)Math.Pow(scale, orders.Length - 1); foreach (string order in orders) { if (bytes > max) return string.Format("{0:##.##} {1}", decimal.Divide(bytes, max), order); max /= scale; } return "0"; } #endregion #region GUI Event Handlers private void buttonStartProxy_Click(object sender, EventArgs e) { if (buttonStartProxy.Text.StartsWith("Start") && m_ProxyRunning.Equals(false)) { proxy = new ProxyManager(textBoxProxyPort.Text, comboBoxListenAddress.Text, comboBoxLoginURL.Text); // disable any gui elements comboBoxListenAddress.Enabled = textBoxProxyPort.Enabled = comboBoxLoginURL.Enabled = false; InitProxyFilters(); proxy.Start(); loadFilterSelectionsToolStripMenuItem.Enabled = saveFilterSelectionsToolStripMenuItem.Enabled = true; // enable any gui elements toolStripSplitButton1.Enabled = toolStripMenuItemPlugins.Enabled = grpUDPFilters.Enabled = grpCapsFilters.Enabled = m_ProxyRunning = true; buttonStartProxy.Text = "Stop Proxy"; buttonStartProxy.Checked = true; if (enableStatisticsToolStripMenuItem.Checked && !timer1.Enabled) timer1.Enabled = true; } else if (buttonStartProxy.Text.StartsWith("Stop") && m_ProxyRunning.Equals(true)) { loadFilterSelectionsToolStripMenuItem.Enabled = saveFilterSelectionsToolStripMenuItem.Enabled = false; // stop the proxy proxy.Stop(); toolStripMenuItemPlugins.Enabled = grpUDPFilters.Enabled = grpCapsFilters.Enabled = m_ProxyRunning = false; buttonStartProxy.Text = "Start Proxy"; buttonStartProxy.Checked = false; comboBoxListenAddress.Enabled = textBoxProxyPort.Enabled = comboBoxLoginURL.Enabled = true; if (!enableStatisticsToolStripMenuItem.Checked && timer1.Enabled) timer1.Enabled = false; } } private void checkBoxCheckAllPackets_CheckedChanged(object sender, EventArgs e) { foreach (ListViewItem item in listViewPacketFilters.Items) { item.Checked = checkBoxCheckAllPackets.Checked; } } private void listViewSessions_ItemSelectionChanged(object sender, ListViewItemSelectionChangedEventArgs e) { if (e.IsSelected && listViewSessions.SelectedItems.Count == 1) { tabControlMain.SelectTab("tabPageInspect"); object tag = e.Item.Tag; if (tag is Session) { Session session = (Session)tag; treeViewXmlResponse.Nodes.Clear(); treeViewXMLRequest.Nodes.Clear(); Be.Windows.Forms.DynamicByteProvider responseBytes = new Be.Windows.Forms.DynamicByteProvider(session.ToBytes(Direction.Incoming)); richTextBoxDecodedResponse.Text = session.ToPrettyString(Direction.Incoming); richTextBoxRawResponse.Text = session.ToRawString(Direction.Incoming); richTextBoxNotationResponse.Text = session.ToStringNotation(Direction.Incoming); hexBoxResponse.ByteProvider = responseBytes; updateTreeView(session.ToXml(Direction.Incoming), treeViewXmlResponse); Be.Windows.Forms.DynamicByteProvider requestBytes = new Be.Windows.Forms.DynamicByteProvider(session.ToBytes(Direction.Outgoing)); richTextBoxDecodedRequest.Text = session.ToPrettyString(Direction.Outgoing); richTextBoxRawRequest.Text = session.ToRawString(Direction.Outgoing); richTextBoxNotationRequest.Text = session.ToStringNotation(Direction.Outgoing); hexBoxRequest.ByteProvider = requestBytes; updateTreeView(session.ToXml(Direction.Outgoing), treeViewXMLRequest); RequestPosition_Changed(this, EventArgs.Empty); ReplyPosition_Changed(this, EventArgs.Empty); } else { richTextBoxDecodedResponse.Text = "Unknown data object encountered: " + tag.GetType().ToString(); } } } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { if (m_ProxyRunning) proxy.Stop(); if (saveOptionsOnExitToolStripMenuItem.Checked) SaveAllSettings("settings.osd"); } // select all items in session list private void sessionSelectAll_Click(object sender, EventArgs e) { foreach (ListViewItem item in listViewSessions.Items) { item.Selected = true; } } // unselect all items in session list private void sessionSelectNone_Click(object sender, EventArgs e) { foreach (ListViewItem item in listViewSessions.Items) { item.Selected = false; } } // invert selection private void sessionInvertSelection_Click(object sender, EventArgs e) { foreach (ListViewItem item in listViewSessions.Items) { item.Selected = !item.Selected; } } // remove all sessions private void sessionRemoveAll_Click(object sender, EventArgs e) { listViewSessions.Items.Clear(); } // remove sessions that are currently selected private void sessionRemoveSelected_Click(object sender, EventArgs e) { foreach (ListViewItem item in listViewSessions.Items) { if (item.Selected) listViewSessions.Items.Remove(item); } } // remove sessions that are not currently selected private void sessionRemoveUnselected_Click(object sender, EventArgs e) { foreach (ListViewItem item in listViewSessions.Items) { if (!item.Selected) listViewSessions.Items.Remove(item); } } // Colorize selected sessions private void sessionMarkSelected_Click(object sender, EventArgs e) { ToolStripMenuItem menu = (ToolStripMenuItem)sender; foreach (ListViewItem item in listViewSessions.Items) { if (item.Selected) item.BackColor = Color.FromName(menu.Text); } sessionSelectNone_Click(sender, e); } // Unmark selected sessions private void sessionUnmarkSelected_Click(object sender, EventArgs e) { foreach (ListViewItem item in listViewSessions.Items) { if (item.Selected) item.BackColor = Color.White; } sessionSelectNone_Click(sender, e); } private void aboutWinGridProxyToolStripMenuItem_Click(object sender, EventArgs e) { AboutBox1 about = new AboutBox1(); about.ShowDialog(); } // Update Request Hexbox status bar with current cursor location private void RequestPosition_Changed(object sender, EventArgs e) { if (hexBoxRequest.ByteProvider != null) { labelHexRequestStatus.Text = String.Format("Ln {0} Col {1} bytes {2}", hexBoxRequest.CurrentLine, hexBoxRequest.CurrentPositionInLine, hexBoxRequest.ByteProvider.Length); buttonSaveRequestHex.Visible = (hexBoxRequest.ByteProvider.Length > 0); } buttonSaveRequestHex.Visible = (hexBoxRequest.ByteProvider != null && hexBoxRequest.ByteProvider.Length > 0); } // Update Response Hexbox status bar with current cursor location void ReplyPosition_Changed(object sender, EventArgs e) { if (hexBoxResponse.ByteProvider != null) { labelHexBoxResponseStatus.Text = String.Format("Ln {0} Col {1} bytes {2}", hexBoxResponse.CurrentLine, hexBoxResponse.CurrentPositionInLine, hexBoxResponse.ByteProvider.Length); } buttonExportRawHex.Visible = (hexBoxResponse.ByteProvider != null && hexBoxResponse.ByteProvider.Length > 0); } // select all specified sessions by packet name private void sessionSelectAllPacketType_Click(object sender, EventArgs e) { foreach (ListViewItem item in listViewSessions.Items) { if (item.SubItems[3].Text.Equals(toolStripMenuItemSelectPacketName.Tag) && !item.Selected) item.Selected = true; } } // stop capturing selected filters private void filterDisableByPacketName_CheckedChanged(object sender, EventArgs e) { if (enableDisableFilterByNameToolStripMenuItem.Tag != null) { ListViewItem found = FindListViewItem(listViewMessageFilters, enableDisableFilterByNameToolStripMenuItem.Tag.ToString(), false); if (found != null) { listViewMessageFilters.Items[found.Index].Checked = enableDisableFilterByNameToolStripMenuItem.Checked; } else { found = FindListViewItem(listViewPacketFilters, enableDisableFilterByNameToolStripMenuItem.Tag.ToString(), false); if (found != null) listViewPacketFilters.Items[found.Index].Checked = enableDisableFilterByNameToolStripMenuItem.Checked; } } } /// /// Setup the context menu prior to it being displayed with specific entries for filtering packets/messages /// /// /// private void contextMenuStripSessions_Opening(object sender, CancelEventArgs e) { if (listViewSessions.SelectedItems.Count == 1) { ListViewItem item = listViewSessions.SelectedItems[0]; string strPacketOrMessage = (item.SubItems[2].Text.Equals(PROTO_PACKETSTRING)) ? "Packets" : "Messages"; enableDisableFilterByNameToolStripMenuItem.Text = String.Format("Capture {0} {1}", item.SubItems[3].Text, strPacketOrMessage); toolStripMenuItemSelectPacketName.Tag = enableDisableFilterByNameToolStripMenuItem.Tag = item.SubItems[3].Text; toolStripMenuItemSelectPacketName.Text = String.Format("All {0} {1}", item.SubItems[3].Text, strPacketOrMessage); enableDisableFilterByNameToolStripMenuItem.Visible = toolStripSeparatorSelectPacketProto.Visible = toolStripSeparatorFilterPacketByName.Visible = toolStripMenuItemSelectPacketName.Visible = true; // find checkstate of selected menuitem in packets or messages filters checkedListBoxes bool ctxChecked = false; if (strPacketOrMessage.Equals("Packets")) { ListViewItem found = FindListViewItem(listViewPacketFilters, toolStripMenuItemSelectPacketName.Tag.ToString(), false); if (found != null) ctxChecked = found.Checked; } else if (strPacketOrMessage.Equals("Messages")) { ListViewItem found = FindListViewItem(listViewMessageFilters, toolStripMenuItemSelectPacketName.Tag.ToString(), false); if (found != null) ctxChecked = found.Checked; } enableDisableFilterByNameToolStripMenuItem.Checked = ctxChecked; } else { // Hide specific selection options on context menu enableDisableFilterByNameToolStripMenuItem.Visible = toolStripSeparatorSelectPacketProto.Visible = toolStripSeparatorFilterPacketByName.Visible = toolStripMenuItemSelectPacketName.Visible = false; } if (listViewSessions.Items.Count > 0) { markToolStripMenuItem2.Enabled = findToolStripMenuItem1.Enabled = toolStripMenuSessionsRemove.Enabled = selectToolStripMenuItem2.Enabled = true; } else { markToolStripMenuItem2.Enabled = findToolStripMenuItem1.Enabled = toolStripMenuSessionsRemove.Enabled = selectToolStripMenuItem2.Enabled = false; } } private void findSessions_Click(object sender, EventArgs e) { FilterOptions opts = new FilterOptions((listViewSessions.SelectedItems.Count > 0)); FormSessionSearch search = new FormSessionSearch(ref opts); search.ShowDialog(); if (!String.IsNullOrEmpty(opts.SearchText)) { Thread sThread = new Thread(delegate() { SearchSessions(opts); }); sThread.Name = "Search"; sThread.Start(); } } // Enable Inject button if box contains text private void richTextBoxInject_TextChanged(object sender, EventArgs e) { buttonInjectPacket.Enabled = (richTextBoxInject.TextLength > 0); } private void buttonInjectPacket_Click(object sender, EventArgs e) { proxy.InjectPacket(richTextBoxInject.Text, true); } private void saveFilterSelectionsToolStripMenuItem_Click(object sender, EventArgs e) { if (saveFileDialog2.ShowDialog() == DialogResult.OK) { SaveAllSettings(saveFileDialog2.FileName); } } private void loadFilterSelectionsToolStripMenuItem_Click(object sender, EventArgs e) { if (openFileDialog2.ShowDialog() == DialogResult.OK) { RestoreSavedSettings(openFileDialog2.FileName); if (listViewSessions.Items.Count > 0) { if (MessageBox.Show("Would you like to apply these settings to the current session list?", "Apply Filter", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.Yes) { listViewSessions.BeginUpdate(); foreach (ListViewItem item in listViewSessions.Items) { ListViewItem found = FindListViewItem(listViewPacketFilters, item.SubItems[3].Text, false); if (found == null) found = FindListViewItem(listViewMessageFilters, item.SubItems[3].Text, false); if (found != null && !found.Checked) listViewSessions.Items.Remove(item); } listViewSessions.EndUpdate(); } } } } private void listViewMessageFilters_ItemChecked(object sender, ItemCheckedEventArgs e) { proxy.AddCapsDelegate(e.Item.Text, e.Item.Checked); } private void listViewPacketFilters_ItemChecked(object sender, ItemCheckedEventArgs e) { if (e.Item.Group.Name.Equals("Packets")) proxy.AddUDPDelegate(PacketTypeFromName(e.Item.Text), e.Item.Checked); } private void checkBoxCheckallCaps_CheckedChanged(object sender, EventArgs e) { foreach (ListViewItem item in listViewMessageFilters.Items) { item.Checked = checkBoxCheckAllMessages.Checked; } } /// /// Start/Stop the statistics gathering timer /// /// /// private void enableStatisticsToolStripMenuItem_CheckedChanged(object sender, EventArgs e) { if (timer1.Enabled && !enableStatisticsToolStripMenuItem.Checked) timer1.Enabled = false; if (!timer1.Enabled && enableStatisticsToolStripMenuItem.Checked) timer1.Enabled = true; } private void saveSessionArchiveToolStripMenuItem_Click(object sender, EventArgs e) { if (saveFileDialog1.ShowDialog() == DialogResult.OK) { OSDMap map = new OSDMap(1); OSDArray sessionArray = new OSDArray(); foreach (ListViewItem item in listViewSessions.Items) { if (item.Tag is Session) { Session data = null; if (item.Tag is SessionCaps) { data = (SessionCaps)item.Tag; } else if (item.Tag is SessionEvent) { data = (SessionEvent)item.Tag; } else if (item.Tag is SessionLogin) { data = (SessionLogin)item.Tag; } else if (item.Tag is SessionPacket) { data = (SessionPacket)item.Tag; } else { Console.WriteLine("Not a valid session type?"); continue; } //Type t = item.Tag.GetType(); //Session data = (SessionCaps)item.Tag; OSDMap session = new OSDMap(); //session["name"] = OSD.FromString(item.Name); //session["image_index"] = OSD.FromInteger(item.ImageIndex); session["id"] = OSD.FromString(item.SubItems[0].Text); //session["protocol"] = OSD.FromString(item.SubItems[1].Text); //session["packet"] = OSD.FromString(item.SubItems[2].Text); //session["size"] = OSD.FromString(item.SubItems[3].Text); //session["host"] = OSD.FromString(item.SubItems[4].Text); session["type"] = OSD.FromString(data.GetType().ToString()); session["tag"] = OSD.FromBinary(data.Serialize()); sessionArray.Add(session); } } map["sessions"] = sessionArray; try { File.WriteAllText(saveFileDialog1.FileName, map.ToString()); } catch (Exception ex) { MessageBox.Show("Exception occurred trying to save session archive: " + ex); } } } private void loadSessionArchiveToolStripMenuItem_Click(object sender, EventArgs e) { if (openFileDialog1.ShowDialog() == DialogResult.OK) { OSDMap map = (OSDMap)OSDParser.DeserializeLLSDNotation(File.ReadAllText(openFileDialog1.FileName)); OSDArray sessionsArray = (OSDArray)map["sessions"]; listViewSessions.Items.Clear(); listViewSessions.BeginUpdate(); for (int i = 0; i < sessionsArray.Count; i++) { OSDMap session = (OSDMap)sessionsArray[i]; Session importedSession = (Session)m_CurrentAssembly.CreateInstance(session["type"].AsString()); importedSession.Deserialize(session["tag"].AsBinary()); ListViewItem addedItem = new ListViewItem(new string[] { session["id"].AsString(), importedSession.TimeStamp.ToString("HH:mm:ss.fff"), importedSession.Protocol, importedSession.Name, importedSession.Length.ToString(), importedSession.Host, importedSession.ContentType}); AddSession(addedItem); //addedItem.ImageIndex = session["image_index"].AsInteger(); addedItem.ImageIndex = (int)importedSession.Direction; addedItem.BackColor = Color.GhostWhite; // give imported items a different color addedItem.Tag = importedSession; } listViewSessions.EndUpdate(); } } //Generic ListView sort event used by filter listviews only private void listViewFilterSorter_ColumnClick(object sender, ColumnClickEventArgs e) { ListView lv = (ListView)sender; ListViewItemComparer columnSorter = new ListViewItemComparer(); columnSorter.column = e.Column; if ((columnSorter.bAscending = (lv.Sorting == SortOrder.Ascending))) lv.Sorting = SortOrder.Descending; else lv.Sorting = SortOrder.Ascending; lv.ListViewItemSorter = columnSorter as IComparer; } private void exitToolStripMenuItem1_Click(object sender, EventArgs e) { // TODO: warn if client is connected! this.Close(); } #endregion GUI Event Handlers #region Helpers private void SaveAllSettings(string fileName) { Store.MessageSessions.Clear(); Store.PacketSessions.Clear(); foreach (ListViewItem item in listViewPacketFilters.Items) { FilterEntryOptions entry = new FilterEntryOptions(); entry.Checked = item.Checked; entry.Type = item.SubItems[1].Text; entry.Group = item.Group.Name; if (!Store.PacketSessions.ContainsKey(item.Text)) Store.PacketSessions.Add(item.Text, entry); } foreach (ListViewItem item in listViewMessageFilters.Items) { FilterEntryOptions entry = new FilterEntryOptions(); entry.Checked = item.Checked; entry.Type = item.SubItems[1].Text; entry.Group = item.Group.Name; if (!Store.MessageSessions.ContainsKey(item.Text)) Store.MessageSessions.Add(item.Text, entry); } Store.StatisticsEnabled = enableStatisticsToolStripMenuItem.Checked; Store.SaveSessionOnExit = saveOptionsOnExitToolStripMenuItem.Checked; Store.AutoCheckNewCaps = autoAddNewDiscoveredMessagesToolStripMenuItem.Checked; Store.SerializeToFile(fileName); } private void RestoreSavedSettings(string fileName) { // load saved settings from OSD Formatted file if (Store.DeserializeFromFile(fileName)) { enableStatisticsToolStripMenuItem.Checked = Store.StatisticsEnabled; saveOptionsOnExitToolStripMenuItem.Checked = Store.SaveSessionOnExit; autoAddNewDiscoveredMessagesToolStripMenuItem.Checked = Store.AutoCheckNewCaps; // Update message filter listview listViewMessageFilters.BeginUpdate(); foreach (KeyValuePair kvp in Store.MessageSessions) { ListViewItem foundMessage = FindListViewItem(listViewPacketFilters, kvp.Key, false); if (foundMessage == null) { ListViewItem addedItem = listViewMessageFilters.Items.Add( new ListViewItem(kvp.Key, listViewMessageFilters.Groups[kvp.Value.Group])); addedItem.Name = kvp.Key; addedItem.Checked = kvp.Value.Checked; addedItem.SubItems.Add(kvp.Value.Type); //addedItem.Group = listViewMessageFilters.Groups[kvp.Value.Group]; addedItem.BackColor = (kvp.Value.Type.Equals(PROTO_CAPABILITIES)) ? Color_Cap : Color_Event; } else { foundMessage.Checked = kvp.Value.Checked; } if (kvp.Value.Type.Equals(PROTO_CAPABILITIES)) { proxy.AddCapsDelegate(kvp.Key, kvp.Value.Checked); } } listViewMessageFilters.EndUpdate(); // updateTreeView packet filter listview listViewPacketFilters.BeginUpdate(); foreach (KeyValuePair kvp in Store.PacketSessions) { ListViewItem foundPacket = FindListViewItem(listViewPacketFilters, kvp.Key, false); if (foundPacket == null) { ListViewItem addedItem = listViewPacketFilters.Items.Add( new ListViewItem(kvp.Key, listViewPacketFilters.Groups[kvp.Value.Group])); addedItem.Name = kvp.Key; addedItem.Checked = kvp.Value.Checked; addedItem.SubItems.Add(kvp.Value.Type); addedItem.BackColor = (kvp.Value.Type.Equals(PROTO_AUTHENTICATE)) ? Color_Login : Color_Packet; } else { foundPacket.Checked = kvp.Value.Checked; } if (kvp.Value.Type.Equals(PROTO_PACKETSTRING)) { proxy.AddUDPDelegate(PacketTypeFromName(kvp.Key), kvp.Value.Checked); } } listViewPacketFilters.EndUpdate(); } } private void InitProxyFilters() { RestoreSavedSettings("settings.osd"); listViewPacketFilters.BeginUpdate(); foreach (string name in Enum.GetNames(typeof(PacketType))) { ListViewItem found = FindListViewItem(listViewPacketFilters, name, false); if (!String.IsNullOrEmpty(name) && found == null) { ListViewItem addedItem = listViewPacketFilters.Items.Add(new ListViewItem(name, listViewPacketFilters.Groups["Packets"])); addedItem.Name = name; addedItem.SubItems.Add(PROTO_PACKETSTRING); } } ListViewItem tmp; if (!listViewPacketFilters.Items.ContainsKey("Login Request")) { tmp = listViewPacketFilters.Items.Add(new ListViewItem("Login Request", listViewPacketFilters.Groups["Login"])); tmp.Name = "Login Request"; tmp.BackColor = Color_Login; tmp.SubItems.Add("Login"); } if (!listViewPacketFilters.Items.ContainsKey("Login Response")) { tmp = listViewPacketFilters.Items.Add(new ListViewItem("Login Response", listViewPacketFilters.Groups["Login"])); tmp.Name = "Login Response"; tmp.BackColor = Color_Login; tmp.SubItems.Add("Login"); } listViewPacketFilters.EndUpdate(); } private static PacketType PacketTypeFromName(string name) { Type packetTypeType = typeof(PacketType); System.Reflection.FieldInfo f = packetTypeType.GetField(name); if (f == null) {//throw new ArgumentException("Bad packet type"); return PacketType.Error; } return (PacketType)Enum.ToObject(packetTypeType, (int)f.GetValue(packetTypeType)); } private void SearchSessions(FilterOptions opts) { if (this.InvokeRequired) { this.BeginInvoke(new MethodInvoker(() => SearchSessions(opts))); } else { int resultCount = 0; foreach (ListViewItem item in listViewSessions.Items) { if (opts.UnMarkPrevious) item.BackColor = Color.White; if (opts.SearchSelected && !item.Selected) { continue; } if ( (opts.MatchCase && (item.SubItems[3].Text.Contains(opts.SearchText) /*|| TagToString(item.Tag, item.SubItems[2].Text).Contains(opts.SearchText)*/) ) // no case matching || ((item.SubItems[3].Text.ToLower().Contains(opts.SearchText.ToLower()) /*|| TagToString(item.Tag, item.SubItems[2].Text).ToLower().Contains(opts.SearchText.ToLower())*/ )) ) { resultCount++; if (opts.MarkMatches) item.BackColor = opts.HighlightMatchColor; if (opts.SelectResults) item.Selected = true; else item.Selected = false; } } //toolStripMainLabel.Text = String.Format("Search found {0} Matches", resultCount); } } #endregion #region XML Tree private void updateTreeView(string xml, TreeView treeView) { try { treeView.Nodes.Clear(); XmlDocument tmpxmldoc = new XmlDocument(); tmpxmldoc.LoadXml(xml); FillTree(tmpxmldoc.DocumentElement, treeView.Nodes); treeView.ExpandAll(); } catch (Exception ex) { Console.WriteLine("Error during xml conversion:" + ex.Message); } } private void FillTree(XmlNode node, TreeNodeCollection parentnode) { // End recursion if the node is a text type if (node == null || node.NodeType == XmlNodeType.Text || node.NodeType == XmlNodeType.CDATA) return; TreeNodeCollection tmptreenodecollection = AddNodeToTree(node, parentnode); // Add all the children of the current node to the treeview foreach (XmlNode tmpchildnode in node.ChildNodes) { FillTree(tmpchildnode, tmptreenodecollection); } } private TreeNodeCollection AddNodeToTree(XmlNode node, TreeNodeCollection parentnode) { TreeNode newchildnode = CreateTreeNodeFromXmlNode(node); // if nothing to add, return the parent item if (newchildnode == null) return parentnode; // add the newly created tree node to its parent if (parentnode != null) parentnode.Add(newchildnode); return newchildnode.Nodes; } private TreeNode CreateTreeNodeFromXmlNode(XmlNode node) { TreeNode tmptreenode = new TreeNode(); if ((node.HasChildNodes) && (node.FirstChild.Value != null)) { tmptreenode = new TreeNode(node.Name); TreeNode tmptreenode2 = new TreeNode(node.FirstChild.Value); tmptreenode.Nodes.Add(tmptreenode2); } else if (node.NodeType != XmlNodeType.CDATA) { tmptreenode = new TreeNode(node.Name); } return tmptreenode; } #endregion #region Timers private void timer1_Tick(object sender, EventArgs e) { if (this.InvokeRequired) { this.BeginInvoke(new MethodInvoker(() => timer1_Tick(sender, e))); } else { label1PacketsOut.Text = String.Format("{0} ({1} bytes)", PacketsOutCounter, PacketsOutBytes); labelPacketsIn.Text = String.Format("{0} ({1} bytes)", PacketsInCounter, PacketsInBytes); labelPacketsTotal.Text = String.Format("{0} ({1} bytes)", PacketsOutCounter + PacketsInCounter, PacketsOutBytes + PacketsInBytes); labelCapsIn.Text = String.Format("{0} ({1} bytes)", CapsInCounter, CapsInBytes); labelCapsOut.Text = String.Format("{0} ({1} bytes)", CapsOutCounter, CapsOutBytes); labelCapsTotal.Text = String.Format("{0} ({1} bytes)", CapsInCounter + CapsOutCounter, CapsOutBytes + CapsInBytes); } } private void timerSessionQueue_Tick(object sender, EventArgs e) { lock (QueuedSessions) { if (QueuedSessions.Count > 0) { listViewSessions.BeginUpdate(); listViewSessions.Items.AddRange(QueuedSessions.ToArray()); if (listViewSessions.Items.Count > 0 && autoscrollToolStripMenuItem.Checked) { listViewSessions.Items[listViewSessions.Items.Count - 1].EnsureVisible(); } listViewSessions.EndUpdate(); QueuedSessions.Clear(); } } } #endregion private void EditToolStripButton_DropDownOpening(object sender, EventArgs e) { if (listViewSessions.Items.Count > 0) { toolStripMenuSessionsRemove.Enabled = removeToolStripMenuItem2.Enabled = selectToolStripMenuItem1.Enabled = saveSessionArchiveToolStripMenuItem.Enabled = toolStripMenuItemRemoveAll.Enabled = true; if (listViewSessions.SelectedItems.Count < listViewSessions.Items.Count) { toolStripMenuItemRemoveUnselected.Enabled = true; } else { toolStripMenuItemRemoveUnselected.Enabled = false; } if (listViewSessions.SelectedItems.Count > 0) { markToolStripMenuItem1.Enabled = toolStripSeparatorSelectPacketProto.Visible = toolStripMenuItemSelectPacketName.Visible = noneToolStripMenuItem2.Enabled = copyToolStripMenuItem1.Enabled = toolStripMenuItemRemoveSelected.Enabled = true; } else { markToolStripMenuItem1.Enabled = toolStripSeparatorSelectPacketProto.Visible = toolStripMenuItemSelectPacketName.Visible = noneToolStripMenuItem2.Enabled = noneToolStripMenuItem2.Enabled = copyToolStripMenuItem1.Enabled = toolStripMenuItemRemoveSelected.Enabled = false; } if (listViewSessions.SelectedItems.Count > 0 && listViewSessions.SelectedItems.Count != listViewSessions.Items.Count) { toolStripMenuItemRemoveUnselected.Enabled = invertToolStripMenuItem1.Enabled = noneToolStripMenuItem2.Enabled = true; } else { toolStripMenuItemRemoveUnselected.Enabled = invertToolStripMenuItem1.Enabled = noneToolStripMenuItem2.Enabled = false; } } else { toolStripMenuSessionsRemove.Enabled = toolStripSeparatorSelectPacketProto.Visible = // toolStripMenuItemSelectProtocol.Visible = toolStripMenuItemSelectPacketName.Visible = findToolStripMenuItem.Enabled = selectToolStripMenuItem1.Enabled = removeToolStripMenuItem2.Enabled = toolStripMenuItemRemoveUnselected.Enabled = copyToolStripMenuItem1.Enabled = markToolStripMenuItem1.Enabled = saveSessionArchiveToolStripMenuItem.Enabled = toolStripMenuItemRemoveAll.Enabled = false; } if (listViewPacketFilters.Items.Count + listViewSessions.Items.Count > 0) { saveFilterSelectionsToolStripMenuItem.Enabled = true; } else { saveFilterSelectionsToolStripMenuItem.Enabled = false; } } private void autoColorizeToolStripMenuItem_Click(object sender, EventArgs e) { if (colorDialog1.ShowDialog() == DialogResult.OK) { //listview.BackColor = colorDialog1.Color; } } private void toolStripMenuItem1_Click(object sender, EventArgs e) { if (pluginManager == null) pluginManager = new FormPluginManager(proxy.Proxy); pluginManager.ShowDialog(); } void Instance_MessageLoggedEvent(object sender, MessageLoggedEventArgs e) { if (this.IsDisposed || this.Disposing) return; if (InvokeRequired) { BeginInvoke(new MethodInvoker(() => Instance_MessageLoggedEvent(sender, e))); } else { string s = String.Format("{0} [{1}] {2} {3}", e.LoggingEvent.TimeStamp, e.LoggingEvent.Level, e.LoggingEvent.RenderedMessage, e.LoggingEvent.ExceptionObject); richTextBoxDebugLog.AppendText(s + "\n"); } } private void richTextBoxDecodedRequest_TextChanged(object sender, EventArgs e) { RichTextBox m_rtb = (RichTextBox)sender; // don't colorize xml! if (m_rtb.Lines.Length <= 0 || m_rtb.Lines[0].StartsWith("\w+|\w+\[\])\]|\((?.*)\)|\s-- (?
\w+|\w+ \[\]) --\s|(?\s\*\*\*\s)|(?\s<\w+>\s|\s<\/\w+>\s)|(?\s\w+\[\d+\]\s)", RegexOptions.ExplicitCapture); MatchCollection matches = typesRegex.Matches(m_rtb.Text); foreach (Match match in matches) { m_rtb.SelectionStart = match.Index + 1; m_rtb.SelectionLength = match.Length - 2; m_rtb.SelectionFont = new Font(m_rtb.Font.FontFamily, m_rtb.Font.Size, FontStyle.Bold); if (!String.IsNullOrEmpty(match.Groups["Type"].Value)) m_rtb.SelectionColor = Color.FromArgb(43, 145, 175); else if (!String.IsNullOrEmpty(match.Groups["Enum"].Value)) m_rtb.SelectionColor = Color.FromArgb(43, 145, 175); else if (!String.IsNullOrEmpty(match.Groups["Header"].Value)) { m_rtb.SelectionColor = Color.Green; m_rtb.SelectionBackColor = Color.LightSteelBlue; } else if (!String.IsNullOrEmpty(match.Groups["BlockSep"].Value)) m_rtb.SelectionColor = Color.Gold; else if (!String.IsNullOrEmpty(match.Groups["Tag"].Value)) { m_rtb.SelectionColor = Color.White; m_rtb.SelectionBackColor = Color.Black; } else if (!String.IsNullOrEmpty(match.Groups["BlockCounter"].Value)) m_rtb.SelectionColor = Color.Green; } } private void AddSession(ListViewItem item) { lock (QueuedSessions) { QueuedSessions.Add(item); } } private void asDecodedTextToolStripMenuItem_Click(object sender, EventArgs e) { if (saveFileDialog1.ShowDialog() == DialogResult.OK) { StringBuilder outString = new StringBuilder(); foreach (ListViewItem item in listViewSessions.Items) { if (item.Tag is Packet) { //outString.AppendLine(DecodePacket.PacketToString((Packet)item.Tag)); outString.AppendLine(PacketDecoder.PacketToString((Packet)item.Tag)); } if (item.Tag is IMessage) { IMessage msg = (IMessage)item.Tag; outString.AppendLine(msg.Serialize().ToString()); } try { File.WriteAllText(saveFileDialog1.FileName, outString.ToString()); } catch (Exception ex) { MessageBox.Show("Exception occurred trying to save session archive: " + ex); } } } } private void richTextBoxDecodedRequest_LinkClicked(object sender, LinkClickedEventArgs e) { System.Diagnostics.Process.Start(e.LinkText); } private void saveSettingsToolStripMenuItem_Click(object sender, EventArgs e) { SaveAllSettings("settings.osd"); } // Column sorter private void listViewSessions_ColumnClick(object sender, ColumnClickEventArgs e) { ListView listView1 = (ListView)sender; ListViewSorter Sorter = new ListViewSorter(); listView1.ListViewItemSorter = Sorter; if (!(listView1.ListViewItemSorter is ListViewSorter)) return; Sorter = (ListViewSorter)listView1.ListViewItemSorter; if (Sorter.LastSort == e.Column) { if (listView1.Sorting == SortOrder.Ascending) listView1.Sorting = SortOrder.Descending; else listView1.Sorting = SortOrder.Ascending; } else { listView1.Sorting = SortOrder.Descending; } Sorter.ByColumn = e.Column; listView1.Sort(); listView1.Columns[e.Column].Width = -2;// = listView1.Columns[e.Column].Text + " " + '\u23BC'; } private void buttonSaveRequestHex_Click(object sender, EventArgs e) { if (hexBoxRequest.ByteProvider != null && hexBoxRequest.ByteProvider.Length > 0) { saveFileDialog3.FileName = listViewSessions.SelectedItems[0].Name; if (saveFileDialog3.ShowDialog() == DialogResult.OK) { byte[] bytes = new byte[hexBoxRequest.ByteProvider.Length]; for (int i = 0; i < hexBoxRequest.ByteProvider.Length; i++) { bytes[i] = hexBoxRequest.ByteProvider.ReadByte(i); } File.WriteAllBytes(saveFileDialog3.FileName, bytes); } } } private void buttonExportRawHex_Click(object sender, EventArgs e) { if (hexBoxResponse.ByteProvider != null && hexBoxResponse.ByteProvider.Length > 0) { saveFileDialog3.FileName = listViewSessions.SelectedItems[0].Name; if (saveFileDialog3.ShowDialog() == DialogResult.OK) { byte[] bytes = new byte[hexBoxResponse.ByteProvider.Length]; for (int i = 0; i < hexBoxResponse.ByteProvider.Length; i++) { bytes[i] = hexBoxResponse.ByteProvider.ReadByte(i); } File.WriteAllBytes(saveFileDialog3.FileName, bytes); } } else { // no bytes to read! } } } public class ListViewSorter : System.Collections.IComparer { public int Compare(object o1, object o2) { if (!(o1 is ListViewItem)) return 0; if (!(o2 is ListViewItem)) return 0; int result; ListViewItem lvi1 = (ListViewItem)o2; ListViewItem lvi2 = (ListViewItem)o1; if (lvi1.ListView.Columns[ByColumn].Tag == null || lvi1.ListView.Columns[ByColumn].Tag == null) { return 0; } if (lvi1.ListView.Columns[ByColumn].Tag.ToString().ToLower().Equals("number")) { float fl1 = float.Parse(lvi1.SubItems[ByColumn].Text); float fl2 = float.Parse(lvi2.SubItems[ByColumn].Text); if (lvi1.ListView.Sorting == SortOrder.Ascending) result = fl1.CompareTo(fl2); else result = fl2.CompareTo(fl1); } else if (lvi1.ListView.Columns[ByColumn].Tag.ToString().ToLower().Equals("string")) { string str1 = lvi1.SubItems[ByColumn].Text; string str2 = lvi2.SubItems[ByColumn].Text; if (lvi1.ListView.Sorting == SortOrder.Ascending) result = String.Compare(str1, str2); else result = String.Compare(str2, str1); } else { return 0; } LastSort = ByColumn; return (result); } public int ByColumn { get { return Column; } set { Column = value; } } int Column = 0; public int LastSort { get { return LastColumn; } set { LastColumn = value; } } int LastColumn = 0; } }