/* * Mentalis.org Packet Monitor * * Copyright ?2003, The KPD-Team * All rights reserved. * http://www.mentalis.org/ * * 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 KPD-Team, 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.Text; using System.Net; using System.Net.Sockets; using System.Runtime.InteropServices; namespace Org.Mentalis.Network.PacketMonitor { /// /// A class that intercepts IP packets on a specific interface. /// /// /// This class only works on Windows 2000 and higher. /// public class PacketMonitor { /// /// Initializes a new instance of the PacketMonitor class. /// /// The interface on which to listen for IP packets. /// The operating system does not support intercepting packets. public PacketMonitor(IPAddress ip) { // make sure the user runs this program on Windows NT 5.0 or higher if (Environment.OSVersion.Platform != PlatformID.Win32NT || Environment.OSVersion.Version.Major < 5) throw new NotSupportedException("This program requires Windows 2000, Windows XP or Windows .NET Server!"); // make sure the user is an Administrator if (!IsUserAnAdmin()) throw new NotSupportedException("This program can only be run by administrators!"); m_IP = ip; m_Buffer = new byte[65535]; } /// /// Cleans up the unmanaged resources. /// ~PacketMonitor() { Stop(); } /// /// Starts listening on the specified interface. /// /// An error occurs when trying to intercept IP packets. public void Start() { if (m_Monitor == null) { try { m_Monitor = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP); m_Monitor.Bind(new IPEndPoint(IP, 0)); byte[] outValue = BitConverter.GetBytes(0); byte[] inValue = BitConverter.GetBytes(1); m_Monitor.IOControl(IOControlCode.ReceiveAll, inValue, outValue); m_Monitor.BeginReceive(m_Buffer, 0, m_Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceive), null); } catch { m_Monitor = null; throw new SocketException(); } } } /// /// Stops listening on the specified interface. /// public void Stop() { if (m_Monitor != null) { m_Monitor.Close(); m_Monitor = null; } } /// /// Called when the socket intercepts an IP packet. /// /// The asynchronous result. private void OnReceive(IAsyncResult ar) { try { int received = m_Monitor.EndReceive(ar); try { if (m_Monitor != null) { byte[] packet = new byte[received]; Array.Copy(Buffer, 0, packet, 0, received); OnNewPacket(new Packet(packet)); } } catch {} // invalid packet; ignore m_Monitor.BeginReceive(Buffer, 0, Buffer.Length, SocketFlags.None, new AsyncCallback(this.OnReceive), null); } catch { Stop(); } } /// /// The interface used to intercept IP packets. /// /// An instance. public IPAddress IP { get { return m_IP; } } /// /// The buffer used to store incoming IP packets. /// /// An array of bytes. protected byte[] Buffer { get { return m_Buffer; } } /// /// Raises an event that indicates a new packet has arrived. /// /// The arrived . protected void OnNewPacket(Packet p) { if (NewPacket != null) NewPacket(this, p); } /// /// Holds all the listeners for the NewPacket event. /// public event NewPacketEventHandler NewPacket; // private variables private Socket m_Monitor; private IPAddress m_IP; private byte[] m_Buffer; private const int IOC_VENDOR = 0x18000000; private const int IOC_IN = -2147483648; //0x80000000; /* copy in parameters */ private const int SIO_RCVALL = IOC_IN | IOC_VENDOR | 1; private const int SECURITY_BUILTIN_DOMAIN_RID = 0x20; private const int DOMAIN_ALIAS_RID_ADMINS = 0x220; /// /// Tests whether the current user is a member of the Administrator's group. /// /// Returns true if the user is a member of the Administrator's group, false if not. private bool IsUserAnAdmin() { byte[] NtAuthority = new byte[6]; NtAuthority[5] = 5; // SECURITY_NT_AUTHORITY IntPtr AdministratorsGroup; int ret = AllocateAndInitializeSid(NtAuthority, 2, SECURITY_BUILTIN_DOMAIN_RID, DOMAIN_ALIAS_RID_ADMINS, 0, 0, 0, 0, 0, 0, out AdministratorsGroup); if (ret != 0) { if (CheckTokenMembership(IntPtr.Zero, AdministratorsGroup, ref ret) == 0) { ret = 0; } FreeSid(AdministratorsGroup); } return (ret != 0); } /// /// The AllocateAndInitializeSid function allocates and initializes a security identifier (SID) with up to eight subauthorities. /// /// Pointer to a SID_IDENTIFIER_AUTHORITY structure, giving the top-level identifier authority value to set in the SID. /// Specifies the number of subauthorities to place in the SID. This parameter also identifies how many of the subauthority parameters have meaningful values. This parameter must contain a value from 1 to 8. /// Subauthority value to place in the SID. /// Subauthority value to place in the SID. /// Subauthority value to place in the SID. /// Subauthority value to place in the SID. /// Subauthority value to place in the SID. /// Subauthority value to place in the SID. /// Subauthority value to place in the SID. /// Subauthority value to place in the SID. /// Pointer to a variable that receives the pointer to the allocated and initialized SID structure. /// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError. [DllImport("advapi32.dll")] private extern static int AllocateAndInitializeSid(byte[] pIdentifierAuthority, byte nSubAuthorityCount, int dwSubAuthority0, int dwSubAuthority1, int dwSubAuthority2, int dwSubAuthority3, int dwSubAuthority4, int dwSubAuthority5, int dwSubAuthority6, int dwSubAuthority7, out IntPtr pSid); /// /// The CheckTokenMembership function determines whether a specified SID is enabled in an access token. /// /// Handle to an access token. The handle must have TOKEN_QUERY access to the token. The token must be an impersonation token. /// Pointer to a SID structure. The CheckTokenMembership function checks for the presence of this SID in the user and group SIDs of the access token. /// Pointer to a variable that receives the results of the check. If the SID is present and has the SE_GROUP_ENABLED attribute, IsMember returns TRUE; otherwise, it returns FALSE. /// If the function succeeds, the return value is nonzero. If the function fails, the return value is zero. To get extended error information, call GetLastError. [DllImport("advapi32.dll")] private extern static int CheckTokenMembership(IntPtr TokenHandle, IntPtr SidToCheck, ref int IsMember); /// /// The FreeSid function frees a security identifier (SID) previously allocated by using the AllocateAndInitializeSid function. /// /// Pointer to the SID structure to free. /// This function does not return a value. [DllImport("advapi32.dll")] private extern static IntPtr FreeSid(IntPtr pSid); // // Tests whether the current user is a member of the Administrator's group. // // Returns TRUE if the user is a member of the Administrator's group, FALSE if not. //[DllImport("shell32.dll")] //private extern static int IsUserAnAdmin(); } /// /// Represents the method that will handle the NewPacket event. /// /// The that intercepted the . /// The newly arrived . public delegate void NewPacketEventHandler(PacketMonitor pm, Packet p); }