예제 #1
0
        /// <summary>
        /// Assign a filter to this device given a filterExpression
        /// </summary>
        /// <param name="filterExpression">The filter expression to compile</param>
        protected void SetFilter(string filterExpression)
        {
            // save the filter string
            _filterString = filterExpression;

            int    res;
            IntPtr bpfProgram;
            string errorString;

            // pcap_setfilter() requires a valid pcap_t which isn't present if
            // the device hasn't been opened
            ThrowIfNotOpen("device is not open");

            // attempt to compile the program
            if (!CompileFilter(PcapHandle, filterExpression, (uint)m_mask, out bpfProgram, out errorString))
            {
                string err = string.Format("Can't compile filter ({0}) : {1} ", filterExpression, errorString);
                throw new PcapException(err);
            }

            //associate the filter with this device
            res = LibPcapSafeNativeMethods.pcap_setfilter(PcapHandle, bpfProgram);

            // Free the program whether or not we were successful in setting the filter
            // we don't want to leak unmanaged memory if we throw an exception.
            FreeBpfProgram(bpfProgram);

            //watch for errors
            if (res < 0)
            {
                errorString = string.Format("Can't set filter ({0}) : {1}", filterExpression, LastError);
                throw new PcapException(errorString);
            }
        }
예제 #2
0
        /// <summary>
        /// Sends a raw packet throgh this device
        /// </summary>
        /// <param name="p">The packet bytes to send</param>
        /// <param name="size">The number of bytes to send</param>
        public override void SendPacket(byte[] p, int size)
        {
            ThrowIfNotOpen("Can't send packet, the device is closed");

            if (size > p.Length)
            {
                throw new ArgumentException("Invalid packetSize value: " + size +
                                            "\nArgument size is larger than the total size of the packet.");
            }

            if (p.Length > Pcap.MAX_PACKET_SIZE)
            {
                throw new ArgumentException("Packet length can't be larger than " + Pcap.MAX_PACKET_SIZE);
            }

            IntPtr p_packet = IntPtr.Zero;

            p_packet = Marshal.AllocHGlobal(size);
            Marshal.Copy(p, 0, p_packet, size);

            int res = LibPcapSafeNativeMethods.pcap_sendpacket(PcapHandle, p_packet, size);

            Marshal.FreeHGlobal(p_packet);
            if (res < 0)
            {
                throw new PcapException("Can't send packet: " + LastError);
            }
        }
예제 #3
0
        /// <summary>
        /// Open the device. To start capturing call the 'StartCapture' function
        /// </summary>
        /// <param name="mode">
        /// A <see cref="DeviceMode"/>
        /// </param>
        /// <param name="read_timeout">
        /// A <see cref="System.Int32"/>
        /// </param>
        public override void Open(DeviceMode mode, int read_timeout)
        {
            if (!Opened)
            {
                StringBuilder errbuf = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE);   //will hold errors

                // set the StopCaptureTimeout value to twice the read timeout to ensure that
                // we wait long enough before considering the capture thread to be stuck when stopping
                // a background capture via StopCapture()
                //
                // NOTE: Doesn't affect Mono if unix poll is available, doesn't affect Linux because
                //       Linux devices have no timeout, they always block. Only affects Windows devices.
                StopCaptureTimeout = new TimeSpan(0, 0, 0, 0, read_timeout * 2);

                PcapHandle = LibPcapSafeNativeMethods.pcap_open_live
                                 (Name,                // name of the device
                                 Pcap.MAX_PACKET_SIZE, // portion of the packet to capture.
                                                       // MAX_PACKET_SIZE (65536) grants that the whole packet will be captured on all the MACs.
                                 (short)mode,          // promiscuous mode
                                 (short)read_timeout,  // read timeout
                                 errbuf);              // error buffer

                if (PcapHandle == IntPtr.Zero)
                {
                    string err = "Unable to open the adapter (" + Name + "). " + errbuf.ToString();
                    throw new PcapException(err);
                }
            }
        }
예제 #4
0
 /// <summary>
 /// Closes the opened dump file
 /// </summary>
 public void DumpClose()
 {
     if (DumpOpened)
     {
         LibPcapSafeNativeMethods.pcap_dump_close(m_pcapDumpHandle);
         m_pcapDumpHandle = IntPtr.Zero;
     }
 }
예제 #5
0
        /// <summary>
        /// Free memory allocated in CompileFilter()
        /// </summary>
        /// <param name="bpfProgram">
        /// A <see cref="IntPtr"/>
        /// </param>
        private static void FreeBpfProgram(IntPtr bpfProgram)
        {
            // free any pcap internally allocated memory from pcap_compile()
            LibPcapSafeNativeMethods.pcap_freecode(bpfProgram);

            // free allocated buffers
            Marshal.FreeHGlobal(bpfProgram);
        }
예제 #6
0
 /// <summary>
 /// Flushes all write buffers of the opened dump file
 /// </summary>
 public void DumpFlush()
 {
     if (DumpOpened)
     {
         int result = LibPcapSafeNativeMethods.pcap_dump_flush(m_pcapDumpHandle);
         if (result < 0)
         {
             throw new PcapException("Error writing buffer to dumpfile. " + LastError);
         }
     }
 }
예제 #7
0
        /// <summary>
        /// Retrieve a list of the current PcapDevices
        /// </summary>
        /// <returns>
        /// A <see cref="List&lt;LibPcapLiveDevice&gt;"/>
        /// </returns>
        private static List <LibPcapLiveDevice> GetDevices()
        {
            var deviceList = new List <LibPcapLiveDevice>();

            var devicePtr   = IntPtr.Zero;
            var errorBuffer = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE);

            int result = LibPcapSafeNativeMethods.pcap_findalldevs(ref devicePtr, errorBuffer);

            if (result < 0)
            {
                throw new PcapException(errorBuffer.ToString());
            }

            IntPtr nextDevPtr = devicePtr;

            while (nextDevPtr != IntPtr.Zero)
            {
                // Marshal pointer into a struct
                PcapUnmanagedStructures.pcap_if pcap_if_unmanaged =
                    (PcapUnmanagedStructures.pcap_if)Marshal.PtrToStructure(nextDevPtr,
                                                                            typeof(PcapUnmanagedStructures.pcap_if));
                PcapInterface pcap_if = new PcapInterface(pcap_if_unmanaged);
                deviceList.Add(new LibPcapLiveDevice(pcap_if));
                nextDevPtr = pcap_if_unmanaged.Next;
            }
            LibPcapSafeNativeMethods.pcap_freealldevs(devicePtr);  // Free unmanaged memory allocation.

            // go through the network interfaces to populate the mac address
            // for each of the devices
            NetworkInterface[] nics = NetworkInterface.GetAllNetworkInterfaces();
            foreach (LibPcapLiveDevice device in deviceList)
            {
                foreach (NetworkInterface adapter in nics)
                {
                    // if the name and id match then we have found the NetworkInterface
                    // that matches the PcapDevice
                    if (device.Name.EndsWith(adapter.Id))
                    {
                        var ipProperties = adapter.GetIPProperties();
                        if (ipProperties.GatewayAddresses.Count != 0)
                        {
                            device.Interface.GatewayAddress = ipProperties.GatewayAddresses[0].Address;
                        }

                        device.Interface.MacAddress   = adapter.GetPhysicalAddress();
                        device.Interface.FriendlyName = adapter.Name;
                    }
                }
            }

            return(deviceList);
        }
예제 #8
0
        /// <summary>
        /// Opens a file for packet writings
        /// </summary>
        /// <param name="fileName"></param>
        public void DumpOpen(string fileName)
        {
            ThrowIfNotOpen("Dump requires an open device");

            if (DumpOpened)
            {
                throw new PcapException("A dump file is already opened");
            }
            m_pcapDumpHandle = LibPcapSafeNativeMethods.pcap_dump_open(PcapHandle, fileName);
            if (!DumpOpened)
            {
                throw new PcapException("Error openning dump file.");
            }
        }
예제 #9
0
        /// <summary>
        /// Opens the device for capture
        /// </summary>
        public override void Open()
        {
            // holds errors
            StringBuilder errbuf = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE);   //will hold errors
            // opens offline pcap file
            IntPtr adapterHandle = LibPcapSafeNativeMethods.pcap_open_offline(this.Name, errbuf);

            // handle error
            if (adapterHandle == IntPtr.Zero)
            {
                string err = "Unable to open offline adapter: " + errbuf.ToString();
                throw new PcapException(err);
            }

            // set the local handle
            this.PcapHandle = adapterHandle;
        }
예제 #10
0
        /// <summary>
        /// Returns true if the filter expression was able to be compiled into a
        /// program without errors
        /// </summary>
        public static bool CheckFilter(string filterExpression,
                                       out string errorString)
        {
            IntPtr bpfProgram;
            IntPtr fakePcap = LibPcapSafeNativeMethods.pcap_open_dead((int)Kavprot.Packets.LinkLayers.Ethernet, Pcap.MAX_PACKET_SIZE);

            uint mask = 0;

            if (!CompileFilter(fakePcap, filterExpression, mask, out bpfProgram, out errorString))
            {
                LibPcapSafeNativeMethods.pcap_close(fakePcap);
                return(false);
            }

            FreeBpfProgram(bpfProgram);

            LibPcapSafeNativeMethods.pcap_close(fakePcap);
            return(true);
        }
예제 #11
0
        /// <summary>
        /// Writes a packet to the pcap dump file associated with this device.
        /// </summary>
        public void Dump(byte[] p, PcapHeader h)
        {
            ThrowIfNotOpen("Cannot dump packet, device is not opened");
            if (!DumpOpened)
            {
                throw new DeviceNotReadyException("Cannot dump packet, dump file is not opened");
            }

            //Marshal packet
            IntPtr pktPtr;

            pktPtr = Marshal.AllocHGlobal(p.Length);
            Marshal.Copy(p, 0, pktPtr, p.Length);

            //Marshal header
            IntPtr hdrPtr = h.MarshalToIntPtr();

            LibPcapSafeNativeMethods.pcap_dump(m_pcapDumpHandle, hdrPtr, pktPtr);

            Marshal.FreeHGlobal(pktPtr);
            Marshal.FreeHGlobal(hdrPtr);
        }
예제 #12
0
        // If CompileFilter() returns true bpfProgram must be freed by passing it to FreeBpfProgram()
        /// or unmanaged memory will be leaked
        private static bool CompileFilter(IntPtr pcapHandle,
                                          string filterExpression,
                                          uint mask,
                                          out IntPtr bpfProgram,
                                          out string errorString)
        {
            int    result;
            string err = String.Empty;

            bpfProgram  = IntPtr.Zero;
            errorString = null;

            //Alocate an unmanaged buffer
            bpfProgram = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PcapUnmanagedStructures.bpf_program)));

            //compile the expressions
            result = LibPcapSafeNativeMethods.pcap_compile(pcapHandle,
                                                           bpfProgram,
                                                           filterExpression,
                                                           1,
                                                           mask);

            if (result < 0)
            {
                err = GetLastError(pcapHandle);

                // free up the program memory
                Marshal.FreeHGlobal(bpfProgram);
                bpfProgram = IntPtr.Zero; // make sure not to pass out a valid pointer

                // set the error string
                errorString = err;

                return(false);
            }

            return(true);
        }
예제 #13
0
        /// <summary>
        /// Gets the next packet captured on this device
        /// </summary>
        /// <param name="p">
        /// A <see cref="Kavprot.Packets.RawPacket"/>
        /// </param>
        /// <returns>
        /// A <see cref="System.Int32"/> that contains the result code
        /// </returns>
        public virtual int GetNextPacket(out Kavprot.Packets.RawPacket p)
        {
            //Pointer to a packet info struct
            IntPtr header = IntPtr.Zero;

            //Pointer to a packet struct
            IntPtr data = IntPtr.Zero;
            int    res  = 0;

            // using an invalid PcapHandle can result in an unmanaged segfault
            // so check for that here
            ThrowIfNotOpen("Device must be opened via Open() prior to use");

            // If a user is calling GetNextPacket() when the background capture loop
            // is also calling into libpcap then bad things can happen
            //
            // The bad behavior I (Chris M.) saw was that the background capture would keep running
            // but no more packets were captured. Took two days to debug and regular users
            // may hit the issue more often so check and report the issue here
            if (Started)
            {
                throw new InvalidOperationDuringBackgroundCaptureException("GetNextPacket() invalid during background capture");
            }

            //Get a packet from winpcap
            res = LibPcapSafeNativeMethods.pcap_next_ex(PcapHandle, ref header, ref data);
            p   = null;

            if (res > 0)
            {
                //Marshal the packet
                if ((header != IntPtr.Zero) && (data != IntPtr.Zero))
                {
                    p = MarshalRawPacket(header, data);
                }
            }
            return(res);
        }
예제 #14
0
        /// <summary>
        /// Closes this adapter
        /// </summary>
        public virtual void Close()
        {
            if (PcapHandle == IntPtr.Zero)
            {
                return;
            }

            if (Started)
            {
                StopCapture();
            }
            LibPcapSafeNativeMethods.pcap_close(PcapHandle);
            PcapHandle = IntPtr.Zero;

            //Remove event handlers
            if (OnPacketArrival != null)
            {
                foreach (PacketArrivalEventHandler pa in OnPacketArrival.GetInvocationList())
                {
                    OnPacketArrival -= pa;
                }
            }
        }
예제 #15
0
        /// <summary>
        /// Retrieve pcap statistics from the adapter
        /// </summary>
        /// <param name="pcap_t">
        /// pcap_t* for the adapter
        /// A <see cref="IntPtr"/>
        /// </param>
        internal PcapStatistics(IntPtr pcap_t)
        {
            IntPtr stat;

            if (Environment.OSVersion.Platform == PlatformID.Unix)
            {
                // allocate memory for the struct
                stat = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PcapUnmanagedStructures.pcap_stat_unix)));
            }
            else
            {
                // allocate memory for the struct
                stat = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PcapUnmanagedStructures.pcap_stat_windows)));
            }

            // retrieve the stats
            var result = (PcapUnmanagedStructures.PcapStatReturnValue)LibPcapSafeNativeMethods.pcap_stats(pcap_t, stat);

            // process the return value
            switch (result)
            {
            case PcapUnmanagedStructures.PcapStatReturnValue.Error:
                // retrieve the error information
                var error = LibPcapLiveDevice.GetLastError(pcap_t);

                // free the stats memory so we don't leak before we throw
                Marshal.FreeHGlobal(stat);

                throw new StatisticsException(error);

            case PcapUnmanagedStructures.PcapStatReturnValue.Success:
                // nothing to do upon success
                break;
            }

            // marshal the unmanaged memory into an object of the proper type
            if (Environment.OSVersion.Platform == PlatformID.Unix)
            {
                var managedStat = (PcapUnmanagedStructures.pcap_stat_unix)Marshal.PtrToStructure(stat,
                                                                                                 typeof(PcapUnmanagedStructures.pcap_stat_unix));

                // copy the values
                this.ReceivedPackets = (uint)managedStat.ps_recv;
                this.DroppedPackets  = (uint)managedStat.ps_drop;
//                this.InterfaceDroppedPackets = (uint)managedStat.ps_ifdrop;
            }
            else
            {
                var managedStat = (PcapUnmanagedStructures.pcap_stat_windows)Marshal.PtrToStructure(stat,
                                                                                                    typeof(PcapUnmanagedStructures.pcap_stat_windows));

                // copy the values
                this.ReceivedPackets = (uint)managedStat.ps_recv;
                this.DroppedPackets  = (uint)managedStat.ps_drop;
//                this.InterfaceDroppedPackets = (uint)managedStat.ps_ifdrop;
            }

            // NOTE: Not supported on unix or winpcap, no need to
            //       put a bogus value in this field
            this.InterfaceDroppedPackets = 0;

            // free the stats
            Marshal.FreeHGlobal(stat);
        }
예제 #16
0
        /// <summary>
        /// The capture thread
        /// </summary>
        protected virtual void CaptureThread()
        {
            if (!Opened)
            {
                throw new DeviceNotReadyException("Capture called before PcapDevice.Open()");
            }

            var usePoll = (this is LibPcapLiveDevice) &&
                          isLibPcap && MonoUnixFound;

            // unix specific code
            int captureFileDescriptor = 0;

            if (usePoll)
            {
                // retrieve the file descriptor of the adapter for use with poll()
                captureFileDescriptor = LibPcapSafeNativeMethods.pcap_fileno(PcapHandle);
                if (captureFileDescriptor == -1)
                {
                    SendCaptureStoppedEvent(CaptureStoppedEventStatus.ErrorWhileCapturing);
                    return;
                }
            }

            LibPcapSafeNativeMethods.pcap_handler Callback = new LibPcapSafeNativeMethods.pcap_handler(PacketHandler);

            // unix specific code
#if UseMonoUnixNativeDirectly
            Pollfd[] pollFds = new Pollfd[1];
#else
            System.Array pollFds        = null;
            object[]     PollParameters = null;
#endif

            // Timeout chosen to allow the capture thread to loop frequently enough
            // to enable it to properly exit when the user requests it to but
            // infrequently enough to cause any noticable performance overhead
            int millisecondTimeout = 500;

            if (usePoll)
            {
#if UseMonoUnixNativeDirectly
                pollFds[0].fd     = captureFileDescriptor;
                pollFds[0].events = PollEvents.POLLPRI | Mono.Unix.Native.PollEvents.POLLIN;
#else
                FieldInfo field;
                pollFds = Array.CreateInstance(PollfdType, 1);

                // create a PollFd struct instance
                var pollFd = Activator.CreateInstance(PollfdType);

                // set the descriptor field
                field = PollfdType.GetField("fd");
                field.SetValue(pollFd, captureFileDescriptor);

                // set the events field
                short eventValue = (short)(POLLIN | POLLPRI); // mask the two together
                field = PollfdType.GetField("events");
                field.SetValue(pollFd, eventValue);

                // set the Pollfd entry
                pollFds.SetValue(pollFd, 0);

                // setup the parameters we will pass to the poll() method
                PollParameters    = new object[2];
                PollParameters[0] = pollFds;
                PollParameters[1] = millisecondTimeout;
#endif
            }

            while (!shouldCaptureThreadStop)
            {
                // unix specific code, we want to poll for packets
                // otherwise if we call pcap_dispatch() the read() will block
                // and won't resume until a packet arrives OR until a signal
                // occurs
                if (usePoll)
                {
                    // block here
#if UseMonoUnixNativeDirectly
                    var result = Mono.Unix.Native.Syscall.poll(pollFds, millisecondTimeout);
#else
                    object o = SyscallType.InvokeMember("poll",
                                                        BindingFlags.InvokeMethod,
                                                        Type.DefaultBinder,
                                                        null,
                                                        PollParameters);
                    int result = (int)o;
#endif

                    // if we have no poll results, just loop
                    if (result <= 0)
                    {
                        continue;
                    }

                    // fall through here to the pcap_dispatch() call
                }

                int res = LibPcapSafeNativeMethods.pcap_dispatch(PcapHandle, m_pcapPacketCount, Callback, IntPtr.Zero);

                // pcap_dispatch() returns the number of packets read or, a status value if the value
                // is negative
                if (res <= 0)
                {
                    switch (res)                    // Check pcap loop status results and notify upstream.
                    {
                    case Pcap.LOOP_USER_TERMINATED: // User requsted loop termination with StopCapture()
                        SendCaptureStoppedEvent(CaptureStoppedEventStatus.CompletedWithoutError);
                        return;

                    case Pcap.LOOP_COUNT_EXHAUSTED:         // m_pcapPacketCount exceeded (successful exit)
                    {
                        // NOTE: pcap_dispatch() returns 0 when a timeout occurrs so to prevent timeouts
                        //       from causing premature exiting from the capture loop we only consider
                        //       exhausted events to cause an escape from the loop when they are from
                        //       offline devices, ie. files read from disk
                        if (this is OfflinePcapDevice)
                        {
                            SendCaptureStoppedEvent(CaptureStoppedEventStatus.CompletedWithoutError);
                            return;
                        }
                        break;
                    }

                    case Pcap.LOOP_EXIT_WITH_ERROR:         // An error occurred whilst capturing.
                        SendCaptureStoppedEvent(CaptureStoppedEventStatus.CompletedWithoutError);
                        return;

                    default:        // This can only be triggered by a bug in libpcap.
                        throw new PcapException("Unknown pcap_loop exit status.");
                    }
                }
                else   // res > 0
                {
                    // if we aren't capturing infinitely we need to account for
                    // the packets that we read
                    if (m_pcapPacketCount != Pcap.InfinitePacketCount)
                    {
                        // take away for the packets read
                        if (m_pcapPacketCount >= res)
                        {
                            m_pcapPacketCount -= res;
                        }
                        else
                        {
                            m_pcapPacketCount = 0;
                        }

                        // no more packets to capture, we are finished capturing
                        if (m_pcapPacketCount == 0)
                        {
                            SendCaptureStoppedEvent(CaptureStoppedEventStatus.CompletedWithoutError);
                            return;
                        }
                    }
                }
            }

            SendCaptureStoppedEvent(CaptureStoppedEventStatus.CompletedWithoutError);
        }
예제 #17
0
        /// <summary>
        /// Retrieve the last error string for a given pcap_t* device
        /// </summary>
        /// <param name="deviceHandle">
        /// A <see cref="IntPtr"/>
        /// </param>
        /// <returns>
        /// A <see cref="System.String"/>
        /// </returns>
        internal static string GetLastError(IntPtr deviceHandle)
        {
            IntPtr err_ptr = LibPcapSafeNativeMethods.pcap_geterr(deviceHandle);

            return(Marshal.PtrToStringAnsi(err_ptr));
        }