/// <summary>
        /// Constructor
        /// </summary>
        /// <param name="linkLayerType">
        /// A <see cref="GodLesZ.Library.Network.Packet.LinkLayers"/>
        /// </param>
        /// <param name="snapshotLength">
        /// A <see cref="System.Nullable&lt;System.Int32&gt;"/>
        /// </param>
        /// <param name="captureFilename">
        /// A <see cref="System.String"/>
        /// </param>
        /// <param name="mode">
        /// A <see cref="FileMode"/>
        /// </param>
        public CaptureFileWriterDevice(GodLesZ.Library.Network.Packet.LinkLayers linkLayerType,
                                       int?snapshotLength,
                                       string captureFilename,
                                       FileMode mode)
        {
            m_pcapFile = captureFilename;

            // append isn't possible without some difficulty and not implemented yet
            if (mode == FileMode.Append)
            {
                throw new System.InvalidOperationException("FileMode.Append is not supported, please contact the developers if you are interested in helping to implementing it");
            }

            if (!snapshotLength.HasValue)
            {
                snapshotLength = Pcap.MAX_PACKET_SIZE;
            }
            else if (snapshotLength > Pcap.MAX_PACKET_SIZE)
            {
                throw new System.InvalidOperationException("snapshotLength > Pcap.MAX_PACKET_SIZE");
            }

            // set the device handle
            PcapHandle = LibPcapSafeNativeMethods.pcap_open_dead((int)linkLayerType, snapshotLength.Value);

            m_pcapDumpHandle = LibPcapSafeNativeMethods.pcap_dump_open(PcapHandle, captureFilename);
            if (m_pcapDumpHandle == IntPtr.Zero)
            {
                throw new PcapException("Error opening dump file '" + LastError + "'");
            }
        }
Exemple #2
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);
            }
        }
        /// <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);
            }
        }
        /// <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.

            return(deviceList);
        }
        /// <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.
                                 (int)mode,            // promiscuous mode
                                 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);
                }
            }
        }
Exemple #6
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);
        }
 /// <summary>
 /// Constructor
 /// </summary>
 /// <param name="device">
 /// A <see cref="LibPcapLiveDevice"/>
 /// </param>
 /// <param name="captureFilename">
 /// A <see cref="System.String"/>
 /// </param>
 public CaptureFileWriterDevice(LibPcapLiveDevice device,
                                string captureFilename) :
     this((GodLesZ.Library.Network.Packet.LinkLayers)LibPcapSafeNativeMethods.pcap_datalink(device.PcapHandle),
          LibPcapSafeNativeMethods.pcap_snapshot(device.PcapHandle),
          captureFilename,
          FileMode.OpenOrCreate)
 {
 }
        /// <summary>
        ///
        /// </summary>
        /// <param name="captureFilename">
        /// A <see cref="System.String"/>
        /// </param>
        public CaptureFileReaderDevice(string captureFilename)
        {
            m_pcapFile = captureFilename;

            // holds errors
            StringBuilder errbuf = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE);             //will hold errors
            // opens offline pcap file
            IntPtr adapterHandle = LibPcapSafeNativeMethods.pcap_open_offline(captureFilename, errbuf);

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

            // set the device handle
            PcapHandle = adapterHandle;
        }
Exemple #9
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)GodLesZ.Library.Network.Packet.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);
        }
        /// <summary>
        /// Writes a packet to the pcap dump file associated with this device.
        /// </summary>
        public void Write(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);
        }
Exemple #11
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);
        }
Exemple #12
0
        /// <summary>
        /// Gets the next packet captured on this device
        /// </summary>
        /// <param name="p">
        /// A <see cref="RawCapture"/>
        /// </param>
        /// <returns>
        /// A <see cref="System.Int32"/> that contains the result code
        /// </returns>
        public virtual int GetNextPacket(out RawCapture 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);
        }
Exemple #13
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;
                }
            }
        }
Exemple #14
0
 /// <summary>
 /// Gets pointers to the next PCAP header and packet data.
 /// Data is only valid until next call to GetNextPacketNative.
 ///
 /// Advanced use only. Intended to allow unmanaged code to avoid the overhead of
 /// marshalling PcapHeader and packet contents to allocated memory.
 /// </summary>
 public int GetNextPacketPointers(ref IntPtr header, ref IntPtr data)
 {
     return(LibPcapSafeNativeMethods.pcap_next_ex(PcapHandle, ref header, ref data));
 }
Exemple #15
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 CaptureFileReaderDevice)
                        {
                            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);
        }
        /// <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);
        }
Exemple #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));
        }