SharpPcap Documentation

repository·master·Indexed 23 days ago

https://github.com/dotpcap/sharppcap

A fully managed, cross-platform .NET library for capturing, injecting, and analyzing network packets from live devices or offline capture files. It interfaces with libpcap (UNIX) and WinPcap/Npcap (Windows) drivers. Key features include BPF filtering, support for reading and writing pcap files, and integration with Packet.Net for deep packet inspection and protocol analysis.

Tokens
5.9K
Snippets
13
Records
22
Agent score
31%

What's inside SharpPcap

  1. Overview of SharpPcap features

    master

    SharpPcap is a fully managed, cross-platform .NET library for capturing, injecting, and analyzing network packets. It interfaces with libpcap (UNIX) or WinPcap/Npcap (Windows) drivers.

    Key Features:

    • Cross-Platform: Runs on Microsoft .NET and Mono for Windows (32/64-bit), Linux (32/64-bit), and macOS.
    • High Performance: Capable of capturing at rates exceeding 3MB/s.
    • Packet Injection: Supports injecting low-level network packets on a given interface.
    • File Handling: Supports reading and writing packet capture files.
    • WinPcap Extensions: Partial support for remote packet capture, setting kernel buffer sizes, using send queues for injection, and collecting network interface statistics.
    • Packet Parsing: Uses the Packet.Net library for deep packet inspection and protocol analysis.
  2. Parse and interpret packet protocols

    master

    SharpPcap integrates with PacketDotNet to allow easy extraction of protocol-specific headers. Use the Extract(Type) method on a captured packet to attempt to parse it into a specific protocol class (e.g., TcpPacket, IpPacket, UdpPacket).

    If the extraction returns a non-null object, you can access protocol-specific properties like SourceAddress, DestinationAddress, or SourcePort directly.

  3. How Packet.Net packet nesting and extraction works

    master

    Packet.Net uses a nesting model rather than an inheritance model to represent network layers. Instead of a TcpPacket inheriting fields from an EthernetPacket, packets are composed of layers. A captured packet might follow a structure like: EthernetPacket $\rightarrow$ IPv4Packet $\rightarrow$ TcpPacket.

    Accessing Nested Packets

    Each packet contains a PayloadPacket property (of type PacketPayloadPacket) and a PayloadData property (of type byte[]).

    To avoid manually traversing the PayloadPacket.PayloadPacket chain, use the Packet.Extract(Type type) method. This method uniformly searches the nested layers to find and return the first packet matching the specified type.

    Recommended Approach: Instead of manual traversal or the deprecated GetEncapsulated() method, use:

    TcpPacket tcpPacket = (TcpPacket)capturedPacket.Extract(typeof(TcpPacket));
  4. Implement high packet rate capture using background queuing

    master

    When packet arrival rates exceed the processing capacity of your OnPacketArrival callback (e.g., due to intensive disk I/O or complex logic), you should queue packets for background processing to avoid dropping packets.

    Recommended Pattern:

    1. Create a thread-safe queue (e.g., a List<RawCapture> protected by a lock object).
    2. In the OnPacketArrival event handler, perform only the minimal work required to add the CaptureEventArgs.Packet to the queue.
    3. Spawn a background thread that periodically checks the queue.
    4. When the background thread finds packets, it should 'swap' the current queue with a new empty one inside a lock to minimize the time the lock is held. This allows the background thread to process the captured batch without blocking the capture callback.
  5. Use SendQueues for optimized packet transmission (WinPcap only)

    master

    For high-performance packet transmission, use the SendQueue class. This is a WinPcap-specific extension that buffers packets at the kernel level, reducing context switches compared to multiple SendPacket() calls.

    Key Workflow

    1. Initialize: Create a SendQueue with a specified size (in bytes).
    2. Queue: Use SendQueue.Add(PcapHeader, buffer/Packet) to add packets. You can pass the same PcapHeader and data received from an OnPacketArrival event.
    3. Transmit: Call SendQueue.Transmit(PcapDevice device, SendQueueTransmitModes transmitMode) to send the entire queue.
    4. Modes: Using SendQueueTransmitModes.Synchronized ensures that the relative timestamps of the packets are respected during transmission, providing high precision at the cost of high CPU usage.
    5. Cleanup: Call SendQueue.Dispose() to free associated buffers.

    Warning: Ensure the link-layer of your source (e.g., a capture file) matches the PcapDataLink of the target adapter, otherwise transmission will be ineffective.

  6. Open an adapter and capture packets using events

    master

    You can capture packets asynchronously by registering a handler to the OnPacketArrival event.

    Configuration Options for Open()

    • DeviceMode.Normal: Captures only packets addressed directly to the adapter.
    • DeviceMode.Promiscuous: Captures all packets on the network segment, regardless of destination.
    • read_timeout: Specifies the timeout in milliseconds. A value of 0 means no timeout (blocks indefinitely if no packets arrive), and -1 causes the read to return immediately.

    Workflow

    1. Register the OnPacketArrival event handler.
    2. Call Open(DeviceMode mode, int read_timeout).
    3. Call StartCapture() to begin non-blocking capture on a new thread.
    4. Call StopCapture() to terminate the process.
    5. Call Close() to release the device.
    // Extract a device from the list
    ICaptureDevice device = devices[i];
    
    // Register our handler function to the 'packet arrival' event
    device.OnPacketArrival += new SharpPcap.PacketArrivalEventHandler(device_OnPacketArrival);
    
    // Open the device for capturing
    int readTimeoutMilliseconds = 1000;
    device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
    
    Console.WriteLine("-- Listening on {0}, hit 'Enter' to stop...", device.Description);
    
    // Start the capturing process
    device.StartCapture();
    
    // Wait for 'Enter' from the user.
    Console.ReadLine();
    
    // Stop the capturing process
    device.StopCapture();
    
    // Close the pcap device
    device.Close();
    
    // Implementation of the handler
    private static void device_OnPacketArrival(object sender, CaptureEventArgs e)
    {
        DateTime time = e.Packet.Timeval.Date;
        int len = e.Packet.Data.Length;
        Console.WriteLine("{0}:{1}:{2},{3} Len={4}",
            time.Hour, time.Minute, time.Second, time.Millisecond, len);
    }
  7. Setup requirements for SharpPcap

    master

    SharpPcap requires a native packet capture driver to be installed on the host system:

    • Windows: You must install WinPcap (or Npcap) before running SharpPcap applications.
    • Unix/Linux/macOS: You must install the libpcap library using your system's package manager.
  8. Gather statistics on network traffic using WinPcap Statistics Mode

    master

    If you are using WinPcap on Windows, you can use CaptureMode.Statistics to gather network statistics efficiently. This mode uses kernel-level packet filters to classify incoming packets, minimizing data copies and context switches compared to traditional user-level calculation.

    To use this feature:

    1. Open the adapter using device.Open().
    2. Set the device.Mode property to CaptureMode.Statistics.
    3. Register a handler for the OnPcapStatistics event.
    4. Call device.StartCapture() to begin gathering data.

    Note: This feature is specific to WinPcap and will not work on other platforms or drivers.

    // Register our handler function to the
    // 'winpcap statistics' event
    device.OnPcapStatistics +=
        new WinPcap.StatisticsModeEventHandler(device_OnPcapStatistics);
    
    // Open the device for capturing
    int readTimeoutMilliseconds = 1000;
    device.Open(DeviceMode.Promiscuous, readTimeoutMilliseconds);
    
    // Handle TCP packets only
    device.Filter = "tcp";
    
    // Set device to statistics mode
    device.Mode = CaptureMode.Statistics;
    
    // Start the capturing process
    device.StartCapture();
    
    // ... later ...
    device.StopCapture();
    device.Close();
  9. Migrate from SharpPcap 5.x to 6.0

    master

    Version 6.0 introduced breaking API changes to improve performance and cleanliness. Key migration steps include:

    • Packet Data: Packet data is now returned via PacketCapture using ReadOnlySpan<byte>. Use PacketCapture.GetPacket() to convert to a RawCapture object if you need to persist it in memory.
    • Resource Management: Devices are now IDisposable. Replace device.Close() calls with using var device = ... or explicit disposal.
    • Renamed Types:
      • OpenFlags is now DeviceModes.
      • DeviceMode is now DeviceModes.
      • NpcapDevice is now LibPcapLiveDevice (recommended for most use cases).
    • API Simplification: Open() methods have been consolidated with default parameters.
    • WinPcap: This is deprecated; switch to LibPcapLiveDevice.
  10. Construct and stitch network packets with Packet.Net

    master

    To create a custom network packet, you instantiate individual protocol packets and then 'stitch' them together by assigning them to the PayloadPacket property of the layer above them.

    Example: Constructing an Ethernet -> IPv4 -> TCP packet

    using PacketDotNet;
    
    // 1. Create the innermost layer (TCP)
    ushort tcpSourcePort = 123;
    ushort tcpDestinationPort = 321;
    var tcpPacket = new TcpPacket(tcpSourcePort, tcpDestinationPort);
    
    // 2. Create the middle layer (IPv4)
    var ipSourceAddress = System.Net.IPAddress.Parse("192.168.1.1");
    var ipDestinationAddress = System.Net.IPAddress.Parse("192.168.1.2");
    var ipPacket = new IPv4Packet(ipSourceAddress, ipDestinationAddress);
    
    // 3. Create the outermost layer (Ethernet)
    var sourceHwAddress = "90-90-90-90-90-90";
    var ethernetSourceHwAddress = System.Net.NetworkInformation.PhysicalAddress.Parse(sourceHwAddress);
    var destinationHwAddress = "80-80-80-80-80-80";
    var ethernetDestinationHwAddress = System.Net.NetworkInformation.PhysicalAddress.Parse(destinationHwAddress);
    
    // EthernetPacketType.None allows the protocol type to be updated based on the payload
    var ethernetPacket = new EthernetPacket(ethernetSourceHwAddress,
        ethernetDestinationHwAddress,
        EthernetPacketType.None);
    
    // 4. Stitch the packets together
    ipPacket.PayloadPacket = tcpPacket;
    ethernetPacket.PayloadPacket = ipPacket;
    
    // 5. Use the packet
    Console.WriteLine(ethernetPacket.ToString());
    byte[] packetBytes = ethernetPacket.Bytes;
    using PacketDotNet;
    
    ushort tcpSourcePort = 123;
    ushort tcpDestinationPort = 321;
    var tcpPacket = new TcpPacket(tcpSourcePort, tcpDestinationPort);
    
    var ipSourceAddress = System.Net.IPAddress.Parse("192.168.1.1");
    var ipDestinationAddress = System.Net.IPAddress.Parse("192.168.1.2");
    var ipPacket = new IPv4Packet(ipSourceAddress, ipDestinationAddress);
    
    var sourceHwAddress = "90-90-90-90-90-90";
    var ethernetSourceHwAddress = System.Net.NetworkInformation.PhysicalAddress.Parse(sourceHwAddress);
    var destinationHwAddress = "80-80-80-80-80-80";
    var ethernetDestinationHwAddress = System.Net.NetworkInformation.PhysicalAddress.Parse(destinationHwAddress);
    
    // NOTE: using EthernetPacketType.None to illustrate that the Ethernet
    //       protocol type is updated based on the packet payload that is
    //       assigned to that particular Ethernet packet
    var ethernetPacket = new EthernetPacket(ethernetSourceHwAddress,
        ethernetDestinationHwAddress,
        EthernetPacketType.None);
    
    // Now stitch all of the packets together
    ipPacket.PayloadPacket = tcpPacket;
    ethernetPacket.PayloadPacket = ipPacket;
    
    // and print out the packet to see that it looks just like we wanted it to
    Console.WriteLine(ethernetPacket.ToString());
    
    // to retrieve the bytes that represent this newly created EthernetPacket use the Bytes property
    byte[] packetBytes = ethernetPacket.Bytes;
  11. Write packets to a capture file

    master

    To save packet data to a file, use CaptureFileWriterDevice. You can write raw byte arrays to the file using the Write() method.

    using var device = new CaptureFileWriterDevice("somefilename.pcap", System.IO.FileMode.Open);
    var bytes = new byte[] { 1, 2, 3, 4 };
    device.Write(bytes);