/// <summary> /// Open the device /// </summary> public override void Open(DeviceConfiguration configuration) { // set the device handle var has_open_dead_with_tstamp_precision_support = Pcap.LibpcapVersion >= new Version(1, 5, 1); var resolution = configuration.TimestampResolution ?? TimestampResolution.Microsecond; if (has_open_dead_with_tstamp_precision_support) { PcapHandle = LibPcapSafeNativeMethods.pcap_open_dead_with_tstamp_precision((int)configuration.LinkLayerType, configuration.Snaplen, (uint)resolution); } else { if (resolution != TimestampResolution.Microsecond) { configuration.RaiseConfigurationFailed( nameof(configuration.TimestampResolution), (int)PcapError.PlatformNotSupported, "pcap version is < 1.5.1, needs pcap_open_dead_with_tstamp_precision()" ); } PcapHandle = LibPcapSafeNativeMethods.pcap_open_dead((int)configuration.LinkLayerType, configuration.Snaplen); } m_pcapDumpHandle = LibPcapSafeNativeMethods.pcap_dump_open(PcapHandle, m_pcapFile); if (m_pcapDumpHandle == IntPtr.Zero) { throw new PcapException("Error opening dump file '" + LastError + "'"); } Active = true; }
static public IReadOnlyList <PcapInterface> GetAllPcapInterfaces(string source, RemoteAuthentication credentials) { var devicePtr = IntPtr.Zero; var errorBuffer = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE); var auth = RemoteAuthentication.CreateAuth(credentials); try { var result = LibPcapSafeNativeMethods.pcap_findalldevs_ex(source, ref auth, ref devicePtr, errorBuffer); if (result < 0) { throw new PcapException(errorBuffer.ToString()); } } catch (TypeLoadException ex) { throw new PlatformNotSupportedException( "Operation is not supported on this platform.", ex ); } var pcapInterfaces = GetAllPcapInterfaces(devicePtr, credentials); // Free unmanaged memory allocation LibPcapSafeNativeMethods.pcap_freealldevs(devicePtr); return(pcapInterfaces); }
/// <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); } }
public static BpfProgram TryCreate(PcapHandle pcapHandle, string filter, int optimize = 1, uint netmask = 0) { var bpfProgram = new BpfProgram(); int result; // Compile the expressions if (ThreadSafeCompile) { result = LibPcapSafeNativeMethods.pcap_compile(pcapHandle, bpfProgram, filter, optimize, netmask); } else { lock (SyncCompile) { result = LibPcapSafeNativeMethods.pcap_compile(pcapHandle, bpfProgram, filter, optimize, netmask); } } if (result < 0) { // Don't use Dispose since we don't want pcap_freecode to be called here Marshal.FreeHGlobal(bpfProgram.handle); bpfProgram.SetHandle(IntPtr.Zero); bpfProgram = null; } return(bpfProgram); }
/// <summary> /// Constructor /// </summary> /// <param name="linkLayerType"> /// A <see cref="PacketDotNet.LinkLayers"/> /// </param> /// <param name="snapshotLength"> /// A <see cref="System.Nullable<System.Int32>"/> /// </param> /// <param name="captureFilename"> /// A <see cref="System.String"/> /// </param> /// <param name="mode"> /// A <see cref="FileMode"/> /// </param> public CaptureFileWriterDevice(PacketDotNet.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 + "'"); } }
/// <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; // 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, 0, out IntPtr bpfProgram, out string 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); } }
protected override bool ReleaseHandle() { LibPcapSafeNativeMethods.pcap_freecode(handle); //Alocate an unmanaged buffer Marshal.FreeHGlobal(handle); return(true); }
/// <summary> /// Closes this adapter /// </summary> public virtual void Close() { if (PcapHandle == IntPtr.Zero) { return; } if (Started) { try { StopCapture(); } catch (Exception) { } } LibPcapSafeNativeMethods.pcap_close(PcapHandle); PcapHandle = IntPtr.Zero; //Remove event handlers if (OnPacketArrival != null) { foreach (PacketArrivalEventHandler pa in OnPacketArrival.GetInvocationList()) { OnPacketArrival -= pa; } } }
public static BpfProgram Create(LinkLayers linktype, string filter, int optimize = 1, uint netmask = 0) { using (var handle = LibPcapSafeNativeMethods.pcap_open_dead((int)linktype, Pcap.MAX_PACKET_SIZE)) { return(Create(handle, filter, optimize, netmask)); } }
public static bool CompileFilter(IntPtr pcapHandle, string filterExpression, uint mask, out IntPtr bpfProgram, out string errorString) { errorString = null; //Alocate an unmanaged buffer bpfProgram = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PcapUnmanagedStructures.bpf_program))); //compile the expressions var result = LibPcapSafeNativeMethods.pcap_compile(pcapHandle, bpfProgram, filterExpression, 1, mask); if (result < 0) { var 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); }
/// <summary> /// Retrieve a list of the current PcapDevices /// </summary> /// <returns> /// A <see cref="List<LibPcapLiveDevice>"/> /// </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); } } }
public 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((PacketDotNet.LinkLayers)LibPcapSafeNativeMethods.pcap_datalink(device.PcapHandle), LibPcapSafeNativeMethods.pcap_snapshot(device.PcapHandle), captureFilename, FileMode.OpenOrCreate) { }
/// <summary> /// Stops the capture process /// /// Throws an exception if the stop capture timeout is exceeded and the /// capture thread was aborted /// </summary> public virtual void StopCapture() { if (Started) { threadCancellationTokenSource.Cancel(); threadCancellationTokenSource = new CancellationTokenSource(); LibPcapSafeNativeMethods.pcap_breakloop(Handle); Task.WaitAny(new[] { captureThread }, StopCaptureTimeout); captureThread = null; } }
/// <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> /// <param name="monitor_mode"> /// A <see cref="MonitorMode"/> /// </param> /// <param name="kernel_buffer_size"> /// A <see cref="System.UInt32"/> /// </param> public override void Open(DeviceMode mode, int read_timeout, MonitorMode monitor_mode, uint kernel_buffer_size) { 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_create( Name, // name of the device errbuf); // error buffer if (PcapHandle == IntPtr.Zero) { string err = "Unable to open the adapter (" + Name + "). " + errbuf.ToString(); throw new PcapException(err); } LibPcapSafeNativeMethods.pcap_set_snaplen(PcapHandle, Pcap.MAX_PACKET_SIZE); if (monitor_mode == MonitorMode.Active) { try { LibPcapSafeNativeMethods.pcap_set_rfmon(PcapHandle, (int)monitor_mode); } catch (System.EntryPointNotFoundException) { throw new PcapException("This implementation of libpcap does not support monitor mode."); } } LibPcapSafeNativeMethods.pcap_set_promisc(PcapHandle, (int)mode); LibPcapSafeNativeMethods.pcap_set_timeout(PcapHandle, read_timeout); if (kernel_buffer_size != 0) { KernelBufferSize = kernel_buffer_size; } var activationResult = LibPcapSafeNativeMethods.pcap_activate(PcapHandle); if (activationResult < 0) { string err = "Unable to activate the adapter (" + Name + "). Return code: " + activationResult.ToString(); throw new PcapException(err); } Active = true; } }
protected unsafe int ManagedTransmit(PcapDevice device, bool synchronized) { if (CurrentLength == 0) { return(0); } var position = 0; var hdrSize = PcapHeader.MemorySize; var sw = new Stopwatch(); fixed(byte *buf = buffer) { var bufPtr = new IntPtr(buf); var firstTimestamp = TimeSpan.FromTicks(PcapHeader.FromPointer(bufPtr).Date.Ticks); while (position < CurrentLength) { // Extract packet from buffer var header = PcapHeader.FromPointer(bufPtr + position); var pktSize = (int)header.CaptureLength; var p = new ReadOnlySpan <byte>(buffer, position + hdrSize, pktSize); if (synchronized) { var timestamp = TimeSpan.FromTicks(header.Date.Ticks); var remainingTime = timestamp.Subtract(firstTimestamp); while (sw.Elapsed < remainingTime) { // Wait for packet time System.Threading.Thread.Sleep((int)remainingTime.TotalMilliseconds / 2); } } // Send the packet int res; unsafe { fixed(byte *p_packet = p) { res = LibPcapSafeNativeMethods.pcap_sendpacket(device.PcapHandle, new IntPtr(p_packet), p.Length); } } // Start Stopwatch after sending first packet sw.Start(); if (res < 0) { break; } position += hdrSize + pktSize; } } return(position); }
/// <summary> /// Runs the program and returns if a given filter applies to the packet /// </summary> /// <param name="bpfProgram"> /// A <see cref="IntPtr"/> /// </param> public bool Matches(ReadOnlySpan <byte> data) { var header = new PcapHeader(0, 0, (uint)data.Length, (uint)data.Length); var hdrPtr = header.MarshalToIntPtr(TimestampResolution.Microsecond); int result; unsafe { fixed(byte *p_packet = data) { result = LibPcapSafeNativeMethods.pcap_offline_filter(this, hdrPtr, new IntPtr(p_packet)); } } Marshal.FreeHGlobal(hdrPtr); return(result != 0); }
/// <summary> /// Close the capture file /// </summary> public override void Close() { if (!Opened) { return; } base.Close(); // close the dump handle if (m_pcapDumpHandle != IntPtr.Zero) { LibPcapSafeNativeMethods.pcap_dump_close(m_pcapDumpHandle); m_pcapDumpHandle = IntPtr.Zero; } }
protected unsafe int NativeTransmit(PcapDevice device, bool synchronized) { int sync = synchronized ? 1 : 0; fixed(byte *buf = buffer) { var pcap_queue = new pcap_send_queue { maxlen = (uint)buffer.Length, len = (uint)CurrentLength, ptrBuff = new IntPtr(buf) }; return(LibPcapSafeNativeMethods.pcap_sendqueue_transmit(device.PcapHandle, ref pcap_queue, sync)); } }
/// <summary> /// Open the device. To start capturing call the 'StartCapture' function /// </summary> /// <param name="configuration"> /// A <see cref="DeviceConfiguration"/> /// </param> public virtual void Open(DeviceConfiguration configuration) { // Caches linkType value. // Open refers to the device being "created" // This method is called by sub-classes in the override method int dataLink = 0; if (Opened) { dataLink = LibPcapSafeNativeMethods.pcap_datalink(Handle); } if (dataLink >= 0) { linkType = (PacketDotNet.LinkLayers)dataLink; } }
/// <summary> /// Sends a raw packet through this device /// </summary> /// <param name="p">The packet bytes to send</param> public void SendPacket(ReadOnlySpan <byte> p, ICaptureHeader header = null) { ThrowIfNotOpen("Can't send packet, the device is closed"); int res; unsafe { fixed(byte *p_packet = p) { res = LibPcapSafeNativeMethods.pcap_sendpacket(Handle, new IntPtr(p_packet), p.Length); } } if (res < 0) { throw new PcapException("Can't send packet: " + LastError); } }
/// <summary> /// Retrieve the next packet data /// </summary> /// <param name="e">Structure to hold the packet data info</param> /// <returns>Status of the operation</returns> public virtual GetPacketStatus GetNextPacket(out PacketCapture e) { //Pointer to a packet info struct IntPtr header = IntPtr.Zero; //Pointer to a packet struct IntPtr data = IntPtr.Zero; // 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"); } if (!PollFileDescriptor()) { e = default; // We checked, there is no data using poll() return(GetPacketStatus.ReadTimeout); } int res; unsafe { //Get a packet from npcap res = LibPcapSafeNativeMethods.pcap_next_ex(PcapHandle, ref header, ref data); var pcapHeader = PcapHeader.FromPointer(header); var dataSpan = new Span <byte>(data.ToPointer(), (int)pcapHeader.CaptureLength); e = new PacketCapture(this, pcapHeader, dataSpan); } return((GetPacketStatus)res); }
private static bool GetIsHardwareAccelerated() { using (var handle = LibPcapSafeNativeMethods.pcap_open_dead(1, 60)) { try { pcap_send_queue queue = default; LibPcapSafeNativeMethods.pcap_sendqueue_transmit(handle, ref queue, 0); return(true); } catch (TypeLoadException) { // Function pcap_sendqueue_transmit not found return(false); } } }
static public IReadOnlyList <PcapInterface> GetAllPcapInterfaces() { 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()); } var pcapInterfaces = GetAllPcapInterfaces(devicePtr, null); // Free unmanaged memory allocation LibPcapSafeNativeMethods.pcap_freealldevs(devicePtr); return(pcapInterfaces); }
/// <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 fakePcap = LibPcapSafeNativeMethods.pcap_open_dead((int)PacketDotNet.LinkLayers.Ethernet, Pcap.MAX_PACKET_SIZE); uint mask = 0; if (!CompileFilter(fakePcap, filterExpression, mask, out IntPtr bpfProgram, out errorString)) { LibPcapSafeNativeMethods.pcap_close(fakePcap); return(false); } FreeBpfProgram(bpfProgram); LibPcapSafeNativeMethods.pcap_close(fakePcap); return(true); }
/// <summary> /// Gets the next packet captured on this device /// </summary> /// <param name="p"> /// A <see cref="RawCapture"/> /// </param> /// <returns> /// A <see cref="int"/> 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"); } p = null; if (!PollFileDescriptor()) { // We checked, there is no data using poll() return(0); } //Get a packet from npcap res = LibPcapSafeNativeMethods.pcap_next_ex(PcapHandle, ref header, ref data); if (res > 0) { //Marshal the packet if ((header != IntPtr.Zero) && (data != IntPtr.Zero)) { p = MarshalRawPacket(header, data); } } return(res); }
/// <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) { errorString = null; using (var pcapHandle = LibPcapSafeNativeMethods.pcap_open_dead((int)PacketDotNet.LinkLayers.Ethernet, Pcap.MAX_PACKET_SIZE)) { var bpfProgram = BpfProgram.TryCreate(pcapHandle, filterExpression); if (bpfProgram == null) { errorString = GetLastError(pcapHandle); return(false); } else { bpfProgram.Dispose(); return(true); } } }
/// <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; }
/// <summary> /// Open the device /// </summary> public override void Open(DeviceConfiguration configuration) { // holds errors StringBuilder errbuf = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE); //will hold errors PcapHandle adapterHandle; // Check if we need to open with a defined precision var has_offline_with_tstamp_precision_support = Pcap.LibpcapVersion >= new Version(1, 5, 1); var resolution = configuration.TimestampResolution ?? TimestampResolution.Microsecond; if (has_offline_with_tstamp_precision_support) { adapterHandle = LibPcapSafeNativeMethods.pcap_open_offline_with_tstamp_precision(m_pcapFile, (uint)resolution, errbuf); } else { // notify the user that they asked for a non-standard resolution but their libpcap // version lacks the necessary function if (resolution != TimestampResolution.Microsecond) { configuration.RaiseConfigurationFailed( nameof(configuration.TimestampResolution), (int)PcapError.PlatformNotSupported, "pcap version is < 1.5.1, needs pcap_open_offline_with_tstamp_precision()" ); } adapterHandle = LibPcapSafeNativeMethods.pcap_open_offline(m_pcapFile, errbuf); } // handle error if (adapterHandle.IsInvalid) { string err = "Unable to open offline adapter: " + errbuf.ToString(); throw new PcapException(err); } // set the device handle Handle = adapterHandle; base.Open(configuration); }