├── .appveyor.yml ├── .circleci └── config.yml ├── .gitattributes ├── .github └── workflows │ └── dotnet-core.yml ├── .gitignore ├── Directory.Build.props ├── Examples ├── CreatingCaptureFile │ ├── CreatingCaptureFile.csproj │ └── Program.cs ├── Example1.IfList │ ├── Example01.IfList.csproj │ └── Example1.IfList.cs ├── Example10.SendQueue │ ├── Example10.SendQueue.csproj │ └── Example10.SendQueues.cs ├── Example11.Statistics │ ├── Example11.Statistics.cs │ └── Example11.Statistics.csproj ├── Example12.PacketManipulation │ ├── Example12.PacketManipulation.csproj │ └── Program.cs ├── Example2.ArpResolve │ ├── Example02.ArpResolve.csproj │ └── Program.cs ├── Example3.BasicCap │ ├── Example03.BasicCap.csproj │ └── Program.cs ├── Example4.BasicCapNoCallback │ ├── Example04.BasicCapNoCallback.csproj │ └── Example4.BasicCapNoCallback.cs ├── Example5.PcapFilter │ ├── Example05.PcapFilter.csproj │ └── Program.cs ├── Example6.DumpTCP │ ├── Example06.DumpTCP.csproj │ └── Program.cs ├── Example9.SendPacket │ ├── Example09.SendPacket.csproj │ └── Example9.SendPacket.cs ├── MultipleFiltersOnDevice │ ├── MultipleFiltersOnDevice.csproj │ └── Program.cs ├── NpcapRemoteCapture │ ├── NpcapRemoteCapture.csproj │ └── Program.cs ├── QueuingPacketsForBackgroundProcessing │ ├── Program.cs │ └── QueuingPacketsForBackgroundProcessing.csproj ├── ReadingCaptureFile │ ├── Program.cs │ └── ReadingCaptureFile.csproj ├── WakeOnLan │ ├── Program.cs │ └── WakeOnLan.csproj ├── WinformsExample │ ├── CaptureForm.Designer.cs │ ├── CaptureForm.cs │ ├── DeviceListForm.Designer.cs │ ├── DeviceListForm.cs │ ├── Program.cs │ ├── Properties │ │ ├── Resources.Designer.cs │ │ └── Resources.resx │ ├── Resources │ │ ├── play_icon_enabled.png │ │ ├── stop_icon_disabled.png │ │ └── stop_icon_enabled.png │ └── WinformsExample.csproj └── WinpkFilterExample │ ├── Program.cs │ └── WinpkFilterExample.csproj ├── History.md ├── LICENSES └── MIT.txt ├── README.md ├── REUSE.toml ├── SharpPcap.sln ├── SharpPcap ├── ARP.cs ├── AuthenticationTypes.cs ├── BaseLiveDevice.cs ├── CaptureDeviceExtensions.cs ├── CaptureDeviceList.cs ├── CaptureStoppedEventHandler.cs ├── CaptureStoppedEventStatus.cs ├── DeviceConfiguration.cs ├── DeviceModes.cs ├── DeviceNotReadyException.cs ├── GetPacketStatus.cs ├── ICaptureDevice.cs ├── ICaptureHeader.cs ├── ICaptureStatistics.cs ├── IInjectionDevice.cs ├── ILiveDevice.cs ├── IPcapDevice.cs ├── InvalidOperationDuringBackgroundCaptureException.cs ├── LibPcap │ ├── BpfProgram.cs │ ├── CaptureFileReaderDevice.cs │ ├── CaptureFileWriterDevice.cs │ ├── CaptureHandleReaderDevice.cs │ ├── CaptureReaderDevice.cs │ ├── LibPcapLiveDevice.cs │ ├── LibPcapLiveDeviceList.cs │ ├── LibPcapSafeNativeMethods.Encoding.cs │ ├── LibPcapSafeNativeMethods.Interop.cs │ ├── LibPcapSafeNativeMethods.Resolver.cs │ ├── LibPcapSafeNativeMethods.cs │ ├── NativeLibrary.cs │ ├── PcapAddress.cs │ ├── PcapDevice.cs │ ├── PcapDeviceCaptureLoop.cs │ ├── PcapHandle.cs │ ├── PcapHeader.cs │ ├── PcapInterface.cs │ ├── PcapStatistics.cs │ ├── PcapUnmanagedStructures.cs │ ├── SendQueue.cs │ ├── SendQueueTransmitModes.cs │ ├── Sockaddr.cs │ └── WindowsNativeMethods.cs ├── MonitorMode.cs ├── PacketArrivalEventHandler.cs ├── PacketCapture.cs ├── Pcap.cs ├── PcapClock.cs ├── PcapError.cs ├── PcapException.cs ├── Posix.cs ├── PosixTimeval.cs ├── RawCapture.cs ├── RemoteAuthentication.cs ├── SharpPcap.csproj ├── Statistics │ ├── CaptureMode.cs │ ├── StatisticsDevice.cs │ └── StatisticsEventArgs.cs ├── StatisticsException.cs ├── TimestampResolution.cs ├── TimestampSourceResolution.cs ├── TimestampType.cs ├── Tunneling │ ├── IPAddressConfiguration.cs │ ├── ITunnelDriver.cs │ ├── TunnelDevice.cs │ ├── TunnelHeader.cs │ ├── Unix │ │ ├── IffFlags.cs │ │ ├── Ifreq.cs │ │ ├── IocDir.cs │ │ ├── NetDeviceFlags.cs │ │ ├── SocketIoctl.cs │ │ └── TuntapDriver.cs │ └── WinTap │ │ ├── TapIoControl.cs │ │ ├── WinFileAccess.cs │ │ ├── WinFileAttributes.cs │ │ ├── WinFileCreation.cs │ │ └── WinTapDriver.cs ├── WinDivert │ ├── IpHelper.cs │ ├── WinDivertAddress.cs │ ├── WinDivertDevice.cs │ ├── WinDivertHeader.cs │ ├── WinDivertLayer.cs │ ├── WinDivertNative.cs │ ├── WinDivertPacketFlags.cs │ └── WinDivertParam.cs └── WinpkFilter │ ├── AdapterMode.cs │ ├── AdapterModes.cs │ ├── DriverHandle.cs │ ├── EthRequest.cs │ ├── HardwarePacketFilters.cs │ ├── IntermediateBuffer.cs │ ├── Kernel32.cs │ ├── NativeMethods.cs │ ├── PacketSource.cs │ ├── TcpAdapterList.cs │ ├── WinpkFilterDevice.cs │ ├── WinpkFilterDriver.cs │ └── WinpkFilterHeader.cs ├── Test ├── ArpTest.cs ├── CaptureDeviceListTest.cs ├── CaptureFileReaderDeviceTest.cs ├── CaptureFileWriterDeviceTest.cs ├── CaptureHandleReaderDeviceTest.cs ├── CheckFilterTest.cs ├── DeviceFixture.cs ├── Exceptions.cs ├── LibPcapLiveDeviceTest.cs ├── LibpcapVersionAttribute.cs ├── LivePcapDeviceListTest.cs ├── LivePcapDeviceSetFilterTest.cs ├── MemorySafetyTests.cs ├── PcapDeviceTest.cs ├── PcapExceptionTest.cs ├── PcapStatisticsTest.cs ├── PcapTest.cs ├── Performance │ ├── PacketParsing.cs │ ├── PacketReading.cs │ └── Rate.cs ├── PosixTimevalTest.cs ├── RemotePcapTests.cs ├── SendPacketTest.cs ├── SendQueueTest.cs ├── Statistics │ └── StatisticsDeviceTest.cs ├── Test.csproj ├── TestHelper.cs ├── TestUser.cs ├── ThreadSafeTests.cs ├── Tunneling │ ├── IpHelper.cs │ ├── TunnelDeviceTest.cs │ └── UdpTester.cs ├── WebHelper.cs ├── WinDivert │ ├── IpHelperTest.cs │ └── WinDivertDeviceTest.cs ├── WinpkFilter │ └── WinpkFilterDeviceTest.cs └── capture_files │ ├── 10k_packets.pcap │ ├── README │ ├── arp_request_response.pcap │ ├── arp_with_vlan.pcap │ ├── ip_packet_bogus_length.pcap │ ├── ipv6_http.pcap │ ├── ipv6_icmpv6_packet.pcap │ ├── tcp.pcap │ ├── tcp_with_extra_bytes.pcap │ ├── test_stream.pcap │ └── udp_dns_request_response.pcap ├── Tutorial ├── README.md └── sharppcap │ └── SharpPcap.png ├── azure-pipelines.yml ├── codecov.yml ├── renovate.json ├── requirements.txt └── scripts ├── Install-npcap.ps1 ├── install-libpcap.sh ├── install-tap.sh ├── install-windows.ps1 ├── install-winpkfilter.ps1 └── test.sh /.appveyor.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Chris Morgan 2 | # SPDX-License-Identifier: MIT 3 | 4 | environment: 5 | # This key is encrypted using secdev's appveyor private key, 6 | # dissected only on master builds (not PRs) and is used during 7 | # npcap OEM installation 8 | npcap_oem_key: 9 | secure: DD54X4DVUeG/IpY41fFPYgl3EfQRTEt5BoibQDm0MeI= 10 | 11 | # Disable automatic AppVeyor build logic 12 | build: off 13 | skip_branch_with_pr: true 14 | branches: 15 | only: 16 | - master 17 | 18 | image: 19 | - Visual Studio 2022 20 | - macos 21 | 22 | for: 23 | - matrix: 24 | only: 25 | - image: Visual Studio 2022 26 | install: 27 | - ps: .\scripts\install-windows.ps1 28 | - ps: .\scripts\Install-npcap.ps1 29 | - ps: .\scripts\install-winpkfilter.ps1 30 | build_script: 31 | - dotnet build -c Release 32 | test_script: 33 | - bash scripts/test.sh --filter "TestCategory!=RemotePcap&TestCategory!=WinDivert" 34 | 35 | - matrix: 36 | only: 37 | - image: macos 38 | install: 39 | - brew install --cask dotnet-sdk 40 | - sudo -E bash scripts/install-libpcap.sh 41 | test_script: 42 | - sudo -E bash scripts/test.sh 43 | -------------------------------------------------------------------------------- /.circleci/config.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Chris Morgan 2 | # SPDX-License-Identifier: MIT 3 | 4 | version: 2.1 5 | 6 | orbs: 7 | win: circleci/windows@5.0.0 8 | 9 | commands: 10 | report: 11 | steps: 12 | - store_test_results: 13 | path: Test/TestResults 14 | - store_artifacts: 15 | path: Test/TestResults 16 | 17 | jobs: 18 | test-windows: 19 | executor: 20 | name: win/default 21 | steps: 22 | - checkout 23 | - run: ./scripts/install-windows.ps1 24 | - run: dotnet build -c Release 25 | - run: bash scripts/test.sh --filter "TestCategory=WinDivert" 26 | - report 27 | 28 | test-ubuntu: 29 | parameters: 30 | libpcap: 31 | description: How to install libpcap 32 | type: string 33 | machine: 34 | image: ubuntu-2004:202201-02 35 | steps: 36 | - checkout 37 | - run: sudo -E bash scripts/install-tap.sh 38 | # Download and compile latest libpcap 39 | - when: 40 | condition: { equal: [ libpcap-script, << parameters.libpcap >> ] } 41 | steps: 42 | - run: sudo -E bash scripts/install-libpcap.sh 43 | # Install libpcap from apt-get 44 | - when: 45 | condition: {not: { equal: [ libpcap-script, << parameters.libpcap >> ] } } 46 | steps: 47 | - run: sudo apt-get install << parameters.libpcap >> 48 | - run: sudo -E bash scripts/test.sh 49 | - run: 50 | when: always 51 | command: sudo chmod -R +r Test/TestResults 52 | - report 53 | 54 | test-arm: 55 | machine: 56 | image: ubuntu-2004:202101-01 57 | resource_class: arm.medium 58 | steps: 59 | - checkout 60 | - run: sudo -E bash scripts/install-tap.sh 61 | - run: sudo apt-get install libpcap0.8 62 | - run: sudo -E bash scripts/test.sh 63 | - run: 64 | when: always 65 | command: sudo chmod -R +r Test/TestResults 66 | - report 67 | 68 | workflows: 69 | version: 2 70 | build: 71 | jobs: 72 | - test-windows 73 | - test-arm 74 | - test-ubuntu: 75 | name: << matrix.libpcap >> 76 | matrix: 77 | parameters: 78 | libpcap: [ "libpcap-script", "libpcap-dev", "libpcap0.8" ] 79 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Copyright 2018 Jan Pluskal 2 | # SPDX-License-Identifier: MIT 3 | 4 | # Auto detect text files and perform LF normalization 5 | * text=auto 6 | 7 | # Custom for Visual Studio 8 | *.cs diff=csharp 9 | *.sln merge=union 10 | *.csproj merge=union 11 | *.vbproj merge=union 12 | *.fsproj merge=union 13 | *.dbproj merge=union 14 | 15 | # Standard to msysgit 16 | *.doc diff=astextplain 17 | *.DOC diff=astextplain 18 | *.docx diff=astextplain 19 | *.DOCX diff=astextplain 20 | *.dot diff=astextplain 21 | *.DOT diff=astextplain 22 | *.pdf diff=astextplain 23 | *.PDF diff=astextplain 24 | *.rtf diff=astextplain 25 | *.RTF diff=astextplain -------------------------------------------------------------------------------- /.github/workflows/dotnet-core.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020 Chris Morgan 2 | # SPDX-License-Identifier: MIT 3 | 4 | name: .NET Core 5 | 6 | on: 7 | push: 8 | branches: [ master ] 9 | pull_request: 10 | branches: [ master ] 11 | 12 | jobs: 13 | build: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | - name: Install libpcap 22 | run: sudo -E bash scripts/install-libpcap.sh 23 | - name: Install tap 24 | run: sudo -E bash scripts/install-tap.sh 25 | - name: Build sharppcap assembly 26 | run: dotnet build SharpPcap/SharpPcap.csproj 27 | - name: Test 28 | run: sudo -E bash scripts/test.sh 29 | env: 30 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 31 | 32 | - run: sudo chmod -R +r Test/TestResults 33 | if: always() 34 | - name: Publish Test Report 35 | uses: mikepenz/action-junit-report@v5 36 | if: always() 37 | with: 38 | report_paths: Test/TestResults/TestResults.xml 39 | - uses: actions/upload-artifact@v4 40 | if: failure() 41 | with: 42 | name: artifacts 43 | path: Test/TestResults/ 44 | 45 | - name: publish on version change 46 | id: publish_nuget 47 | uses: alirezanet/publish-nuget@v3.1.0 48 | with: 49 | # Filepath of the project to be packaged, relative to root of repository 50 | PROJECT_FILE_PATH: SharpPcap/SharpPcap.csproj 51 | 52 | # API key to authenticate with NuGet server 53 | NUGET_KEY: ${{secrets.NUGET_API_KEY}} 54 | 55 | # Flag to toggle pushing symbols along with nuget package to the server, disabled by default 56 | INCLUDE_SYMBOLS: true 57 | 58 | license-check: 59 | # We use https://github.com/fsfe/reuse-tool to ensure EVERY file has correct license and copyright info 60 | # Either in the file itself, or in .reuse\dep5 for binary files and files that don't support comments 61 | runs-on: ubuntu-latest 62 | steps: 63 | - uses: actions/checkout@v4 64 | - uses: actions/setup-python@v5 65 | with: 66 | python-version: '3.13' 67 | - run: pip install -r requirements.txt 68 | - run: reuse lint 69 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 5 | 6 | 7 | true 8 | full 9 | true 10 | 8.0 11 | 12 | 13 | -------------------------------------------------------------------------------- /Examples/CreatingCaptureFile/CreatingCaptureFile.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/Example1.IfList/Example01.IfList.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/Example1.IfList/Example1.IfList.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | using System; 4 | using SharpPcap; 5 | 6 | namespace Example1 7 | { 8 | /// 9 | /// Obtaining the device list 10 | /// 11 | public class Program 12 | { 13 | /// 14 | /// Obtaining the device list 15 | /// 16 | public static void Main(string[] args) 17 | { 18 | // Print SharpPcap version 19 | var ver = Pcap.SharpPcapVersion; 20 | Console.WriteLine("SharpPcap {0}, Example1.IfList.cs", ver); 21 | 22 | // Retrieve the device list 23 | var devices = CaptureDeviceList.Instance; 24 | 25 | // If no devices were found print an error 26 | if (devices.Count < 1) 27 | { 28 | Console.WriteLine("No devices were found on this machine"); 29 | return; 30 | } 31 | 32 | Console.WriteLine("\nThe following devices are available on this machine:"); 33 | Console.WriteLine("----------------------------------------------------\n"); 34 | 35 | /* Scan the list printing every entry */ 36 | foreach (var dev in devices) 37 | Console.WriteLine("{0}\n", dev.ToString()); 38 | 39 | Console.Write("Hit 'Enter' to exit..."); 40 | Console.ReadLine(); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Examples/Example10.SendQueue/Example10.SendQueue.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/Example11.Statistics/Example11.Statistics.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/Example12.PacketManipulation/Example12.PacketManipulation.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/Example2.ArpResolve/Example02.ArpResolve.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/Example2.ArpResolve/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using SharpPcap; 4 | using SharpPcap.LibPcap; 5 | 6 | // Copyright (c) 2006 Tamir Gal, http://www.tamirgal.com, All rights reserved. 7 | // 8 | // SPDX-License-Identifier: MIT 9 | 10 | namespace Example2 11 | { 12 | /// 13 | /// A sample showing how to use the Address Resolution Protocol (ARP) 14 | /// with the SharpPcap library. 15 | /// 16 | public class Program 17 | { 18 | public static void Main(string[] args) 19 | { 20 | // Print SharpPcap version 21 | var ver = Pcap.SharpPcapVersion; 22 | Console.WriteLine("SharpPcap {0}, Example2.ArpResolve.cs\n", ver); 23 | 24 | // Retrieve the device list 25 | var devices = LibPcapLiveDeviceList.Instance; 26 | 27 | // If no devices were found print an error 28 | if (devices.Count < 1) 29 | { 30 | Console.WriteLine("No devices were found on this machine"); 31 | return; 32 | } 33 | 34 | Console.WriteLine("The following devices are available on this machine:"); 35 | Console.WriteLine("----------------------------------------------------"); 36 | Console.WriteLine(); 37 | 38 | int i = 0; 39 | 40 | // Print out the available devices 41 | foreach (var dev in devices) 42 | { 43 | Console.WriteLine("{0}) {1} {2}", i, dev.Name, dev.Description); 44 | i++; 45 | } 46 | 47 | Console.WriteLine(); 48 | Console.Write("-- Please choose a device for sending the ARP request: "); 49 | i = int.Parse(Console.ReadLine()); 50 | 51 | var device = devices[i]; 52 | 53 | System.Net.IPAddress ip; 54 | 55 | // loop until a valid ip address is parsed 56 | while (true) 57 | { 58 | Console.Write("-- Please enter IP address to be resolved by ARP: "); 59 | if (IPAddress.TryParse(Console.ReadLine(), out ip)) 60 | break; 61 | Console.WriteLine("Bad IP address format, please try again"); 62 | } 63 | 64 | // Create a new ARP resolver 65 | ARP arper = new ARP(device); 66 | 67 | // print the resolved address or indicate that none was found 68 | var resolvedMacAddress = arper.Resolve(ip); 69 | if (resolvedMacAddress == null) 70 | { 71 | Console.WriteLine("Timeout, no mac address found for ip of " + ip); 72 | } 73 | else 74 | { 75 | Console.WriteLine(ip + " is at: " + arper.Resolve(ip)); 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /Examples/Example3.BasicCap/Example03.BasicCap.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/Example3.BasicCap/Program.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | using System; 4 | using SharpPcap; 5 | using SharpPcap.LibPcap; 6 | 7 | namespace Example3 8 | { 9 | /// 10 | /// Basic capture example 11 | /// 12 | public class Program 13 | { 14 | public static void Main() 15 | { 16 | // Print SharpPcap version 17 | var ver = Pcap.SharpPcapVersion; 18 | Console.WriteLine("SharpPcap {0}, Example3.BasicCap.cs", ver); 19 | 20 | // Retrieve the device list 21 | var devices = CaptureDeviceList.Instance; 22 | 23 | // If no devices were found print an error 24 | if (devices.Count < 1) 25 | { 26 | Console.WriteLine("No devices were found on this machine"); 27 | return; 28 | } 29 | 30 | Console.WriteLine(); 31 | Console.WriteLine("The following devices are available on this machine:"); 32 | Console.WriteLine("----------------------------------------------------"); 33 | Console.WriteLine(); 34 | 35 | int i = 0; 36 | 37 | // Print out the devices 38 | foreach (var dev in devices) 39 | { 40 | /* Description */ 41 | Console.WriteLine("{0}) {1} {2}", i, dev.Name, dev.Description); 42 | i++; 43 | } 44 | 45 | Console.WriteLine(); 46 | Console.Write("-- Please choose a device to capture: "); 47 | i = int.Parse(Console.ReadLine()); 48 | 49 | using var device = devices[i]; 50 | 51 | // Register our handler function to the 'packet arrival' event 52 | device.OnPacketArrival += 53 | new PacketArrivalEventHandler(device_OnPacketArrival); 54 | 55 | // Open the device for capturing 56 | int readTimeoutMilliseconds = 1000; 57 | device.Open(mode: DeviceModes.Promiscuous | DeviceModes.DataTransferUdp | DeviceModes.NoCaptureLocal, read_timeout: readTimeoutMilliseconds); 58 | 59 | Console.WriteLine(); 60 | Console.WriteLine("-- Listening on {0} {1}, hit 'Enter' to stop...", 61 | device.Name, device.Description); 62 | 63 | // Start the capturing process 64 | device.StartCapture(); 65 | 66 | // Wait for 'Enter' from the user. 67 | Console.ReadLine(); 68 | 69 | // Stop the capturing process 70 | device.StopCapture(); 71 | 72 | Console.WriteLine("-- Capture stopped."); 73 | 74 | // Print out the device statistics 75 | Console.WriteLine(device.Statistics.ToString()); 76 | } 77 | 78 | /// 79 | /// Prints the time and length of each received packet 80 | /// 81 | private static void device_OnPacketArrival(object sender, PacketCapture e) 82 | { 83 | var time = e.Header.Timeval.Date; 84 | var len = e.Data.Length; 85 | var rawPacket = e.GetPacket(); 86 | Console.WriteLine("{0}:{1}:{2},{3} Len={4}", 87 | time.Hour, time.Minute, time.Second, time.Millisecond, len); 88 | Console.WriteLine(rawPacket.ToString()); 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /Examples/Example4.BasicCapNoCallback/Example04.BasicCapNoCallback.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/Example4.BasicCapNoCallback/Example4.BasicCapNoCallback.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | using System; 4 | using SharpPcap; 5 | 6 | namespace Example4 7 | { 8 | /// 9 | /// Basic capture example with no callback 10 | /// 11 | public class Program 12 | { 13 | public static void Main() 14 | { 15 | // Print SharpPcap version 16 | var ver = Pcap.SharpPcapVersion; 17 | Console.WriteLine("SharpPcap {0}, Example4.BasicCapNoCallback.cs", ver); 18 | 19 | // Retrieve the device list 20 | var devices = CaptureDeviceList.Instance; 21 | 22 | // If no devices were found print an error 23 | if (devices.Count < 1) 24 | { 25 | Console.WriteLine("No devices were found on this machine"); 26 | return; 27 | } 28 | 29 | Console.WriteLine(); 30 | Console.WriteLine("The following devices are available on this machine:"); 31 | Console.WriteLine("----------------------------------------------------"); 32 | Console.WriteLine(); 33 | 34 | int i = 0; 35 | 36 | // Print out the devices 37 | foreach (var dev in devices) 38 | { 39 | Console.WriteLine("{0}) {1} {2}", i, dev.Name, dev.Description); 40 | i++; 41 | } 42 | 43 | Console.WriteLine(); 44 | Console.Write("-- Please choose a device to capture: "); 45 | i = int.Parse(Console.ReadLine()); 46 | 47 | using var device = devices[i]; 48 | 49 | // Open the device for capturing 50 | int readTimeoutMilliseconds = 1000; 51 | device.Open(DeviceModes.Promiscuous, readTimeoutMilliseconds); 52 | 53 | Console.WriteLine(); 54 | Console.WriteLine("-- Listening on {0}...", 55 | device.Description); 56 | 57 | RawCapture packet; 58 | 59 | // Capture packets using GetNextPacket() 60 | PacketCapture e; 61 | GetPacketStatus retval; 62 | while ((retval = device.GetNextPacket(out e)) == GetPacketStatus.PacketRead) 63 | { 64 | packet = e.GetPacket(); 65 | 66 | // Prints the time and length of each received packet 67 | var time = packet.Timeval.Date; 68 | var len = packet.Data.Length; 69 | Console.WriteLine("{0}:{1}:{2},{3} Len={4}", 70 | time.Hour, time.Minute, time.Second, time.Millisecond, len); 71 | } 72 | 73 | // Print out the device statistics 74 | Console.WriteLine(device.Statistics.ToString()); 75 | 76 | Console.WriteLine("-- Timeout elapsed, capture stopped, device closed."); 77 | Console.Write("Hit 'Enter' to exit..."); 78 | Console.ReadLine(); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Examples/Example5.PcapFilter/Example05.PcapFilter.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/Example5.PcapFilter/Program.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | using System; 4 | using SharpPcap; 5 | 6 | namespace Example5 7 | { 8 | public class Program 9 | { 10 | public static void Main() 11 | { 12 | // Print SharpPcap version 13 | var ver = Pcap.SharpPcapVersion; 14 | Console.WriteLine("SharpPcap {0}, Example5.PcapFilter.cs\n", ver); 15 | 16 | // Retrieve the device list 17 | var devices = CaptureDeviceList.Instance; 18 | 19 | // If no devices were found print an error 20 | if (devices.Count < 1) 21 | { 22 | Console.WriteLine("No devices were found on this machine"); 23 | return; 24 | } 25 | 26 | Console.WriteLine("The following devices are available on this machine:"); 27 | Console.WriteLine("----------------------------------------------------"); 28 | Console.WriteLine(); 29 | 30 | int i = 0; 31 | 32 | // Scan the list printing every entry 33 | foreach (var dev in devices) 34 | { 35 | Console.WriteLine("{0}) {1}", i, dev.Description); 36 | i++; 37 | } 38 | 39 | Console.WriteLine(); 40 | Console.Write("-- Please choose a device to capture: "); 41 | i = int.Parse(Console.ReadLine()); 42 | 43 | using var device = devices[i]; 44 | 45 | //Register our handler function to the 'packet arrival' event 46 | device.OnPacketArrival += 47 | new PacketArrivalEventHandler(device_OnPacketArrival); 48 | 49 | //Open the device for capturing 50 | int readTimeoutMilliseconds = 1000; 51 | device.Open(DeviceModes.Promiscuous, readTimeoutMilliseconds); 52 | 53 | // tcpdump filter to capture only TCP/IP packets 54 | string filter = "ip and tcp"; 55 | device.Filter = filter; 56 | 57 | Console.WriteLine(); 58 | Console.WriteLine 59 | ("-- The following tcpdump filter will be applied: \"{0}\"", 60 | filter); 61 | Console.WriteLine 62 | ("-- Listening on {0}, hit 'Ctrl-C' to exit...", 63 | device.Description); 64 | 65 | // Start capture packets 66 | device.Capture(); 67 | 68 | } 69 | 70 | /// 71 | /// Prints the time and length of each received packet 72 | /// 73 | private static void device_OnPacketArrival(object sender, PacketCapture e) 74 | { 75 | var time = e.Header.Timeval.Date; 76 | var len = e.Data.Length; 77 | Console.WriteLine("{0}:{1}:{2},{3} Len={4}", 78 | time.Hour, time.Minute, time.Second, time.Millisecond, len); 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Examples/Example6.DumpTCP/Example06.DumpTCP.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/Example6.DumpTCP/Program.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | using System; 4 | using SharpPcap; 5 | 6 | namespace Example6 7 | { 8 | public class Program 9 | { 10 | public static void Main() 11 | { 12 | var ver = Pcap.SharpPcapVersion; 13 | /* Print SharpPcap version */ 14 | Console.WriteLine("SharpPcap {0}, Example6.DumpTCP.cs", ver); 15 | Console.WriteLine(); 16 | 17 | /* Retrieve the device list */ 18 | var devices = CaptureDeviceList.Instance; 19 | 20 | /*If no device exists, print error */ 21 | if (devices.Count < 1) 22 | { 23 | Console.WriteLine("No device found on this machine"); 24 | return; 25 | } 26 | 27 | Console.WriteLine("The following devices are available on this machine:"); 28 | Console.WriteLine("----------------------------------------------------"); 29 | Console.WriteLine(); 30 | 31 | int i = 0; 32 | 33 | /* Scan the list printing every entry */ 34 | foreach (var dev in devices) 35 | { 36 | /* Description */ 37 | Console.WriteLine("{0}) {1} {2}", i, dev.Name, dev.Description); 38 | i++; 39 | } 40 | 41 | Console.WriteLine(); 42 | Console.Write("-- Please choose a device to capture: "); 43 | i = int.Parse(Console.ReadLine()); 44 | 45 | using var device = devices[i]; 46 | 47 | //Register our handler function to the 'packet arrival' event 48 | device.OnPacketArrival += 49 | new PacketArrivalEventHandler(device_OnPacketArrival); 50 | 51 | // Open the device for capturing 52 | int readTimeoutMilliseconds = 1000; 53 | device.Open(DeviceModes.Promiscuous, readTimeoutMilliseconds); 54 | 55 | //tcpdump filter to capture only TCP/IP packets 56 | string filter = "ip and tcp"; 57 | device.Filter = filter; 58 | 59 | Console.WriteLine(); 60 | Console.WriteLine 61 | ("-- The following tcpdump filter will be applied: \"{0}\"", 62 | filter); 63 | Console.WriteLine 64 | ("-- Listening on {0}, hit 'Ctrl-C' to exit...", 65 | device.Description); 66 | 67 | // Start capture 'INFINTE' number of packets 68 | device.Capture(); 69 | 70 | } 71 | 72 | /// 73 | /// Prints the time, length, src ip, src port, dst ip and dst port 74 | /// for each TCP/IP packet received on the network 75 | /// 76 | private static void device_OnPacketArrival(object sender, PacketCapture e) 77 | { 78 | var time = e.Header.Timeval.Date; 79 | var len = e.Data.Length; 80 | var rawPacket = e.GetPacket(); 81 | 82 | var packet = PacketDotNet.Packet.ParsePacket(rawPacket.LinkLayerType, rawPacket.Data); 83 | 84 | var tcpPacket = packet.Extract(); 85 | if (tcpPacket != null) 86 | { 87 | var ipPacket = (PacketDotNet.IPPacket)tcpPacket.ParentPacket; 88 | System.Net.IPAddress srcIp = ipPacket.SourceAddress; 89 | System.Net.IPAddress dstIp = ipPacket.DestinationAddress; 90 | int srcPort = tcpPacket.SourcePort; 91 | int dstPort = tcpPacket.DestinationPort; 92 | 93 | Console.WriteLine("{0}:{1}:{2},{3} Len={4} {5}:{6} -> {7}:{8}", 94 | time.Hour, time.Minute, time.Second, time.Millisecond, len, 95 | srcIp, srcPort, dstIp, dstPort); 96 | } 97 | } 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /Examples/Example9.SendPacket/Example09.SendPacket.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/Example9.SendPacket/Example9.SendPacket.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | using System; 4 | using SharpPcap; 5 | 6 | namespace Example9 7 | { 8 | public class Program 9 | { 10 | public static void Main() 11 | { 12 | // Print SharpPcap version 13 | var ver = Pcap.SharpPcapVersion; 14 | Console.WriteLine("SharpPcap {0}, Example9.SendPacket.cs\n", ver); 15 | 16 | // Retrieve the device list 17 | var devices = CaptureDeviceList.Instance; 18 | 19 | // If no devices were found print an error 20 | if (devices.Count < 1) 21 | { 22 | Console.WriteLine("No devices were found on this machine"); 23 | return; 24 | } 25 | 26 | Console.WriteLine("The following devices are available on this machine:"); 27 | Console.WriteLine("----------------------------------------------------"); 28 | Console.WriteLine(); 29 | 30 | int i = 0; 31 | 32 | // Print out the available devices 33 | foreach (var dev in devices) 34 | { 35 | Console.WriteLine("{0}) {1}", i, dev.Description); 36 | i++; 37 | } 38 | 39 | Console.WriteLine(); 40 | Console.Write("-- Please choose a device to send a packet on: "); 41 | i = int.Parse(Console.ReadLine()); 42 | 43 | using var device = devices[i]; 44 | 45 | Console.Write("-- This will send a random packet out this interface, " + 46 | "continue? [YES|no]"); 47 | string resp = Console.ReadLine().ToLower(); 48 | 49 | // If user refused, exit program 50 | if ((resp != "") && (!resp.StartsWith("y"))) 51 | { 52 | Console.WriteLine("Cancelled by user!"); 53 | return; 54 | } 55 | 56 | //Open the device 57 | device.Open(); 58 | 59 | //Generate a random packet 60 | byte[] bytes = GetRandomPacket(); 61 | 62 | try 63 | { 64 | //Send the packet out the network device 65 | device.SendPacket(bytes); 66 | Console.WriteLine("-- Packet sent successfuly."); 67 | } 68 | catch (Exception e) 69 | { 70 | Console.WriteLine("-- " + e.Message); 71 | } 72 | 73 | Console.Write("Hit 'Enter' to exit..."); 74 | Console.ReadLine(); 75 | } 76 | 77 | /// 78 | /// Generates a random packet of size 200 79 | /// 80 | private static byte[] GetRandomPacket() 81 | { 82 | byte[] packet = new byte[200]; 83 | Random rand = new Random(); 84 | rand.NextBytes(packet); 85 | return packet; 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Examples/MultipleFiltersOnDevice/MultipleFiltersOnDevice.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/NpcapRemoteCapture/NpcapRemoteCapture.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/NpcapRemoteCapture/Program.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | using System; 4 | using System.Net; 5 | using SharpPcap; 6 | using SharpPcap.LibPcap; 7 | 8 | namespace NpcapRemoteCapture 9 | { 10 | /// 11 | /// Example showing how to use the remote capture feature of Npcap 12 | /// 13 | public class Program 14 | { 15 | private static readonly int rpcapDefaultPort = 2002; 16 | 17 | static void PrintUsage(string programName) 18 | { 19 | Console.WriteLine("{0} ipAddress [port] - port defaults to {1} (rpcapd default port)", programName, rpcapDefaultPort); 20 | } 21 | 22 | static void Main(string[] args) 23 | { 24 | if ((args.Length < 1) || (args.Length > 2)) 25 | { 26 | PrintUsage("NpcapRemoteCapture"); 27 | return; 28 | } 29 | 30 | // ensure that a remote capture daemon has been started by running 31 | // 'rpcapd.exe' on the remote server. By default port 2003 is used for the server 32 | 33 | var ipAddress = System.Net.IPAddress.Parse(args[0]); 34 | var port = rpcapDefaultPort; 35 | if (args.Length == 2) 36 | port = Int32.Parse(args[1]); 37 | 38 | var remoteInterfaces = PcapInterface.GetAllPcapInterfaces(new IPEndPoint(ipAddress, port), null); 39 | foreach (var dev in remoteInterfaces) 40 | { 41 | Console.WriteLine("device: {0}", dev.ToString()); 42 | } 43 | 44 | // open the device for capture 45 | using var device = new LibPcapLiveDevice(remoteInterfaces[0]); 46 | 47 | device.OnPacketArrival += new PacketArrivalEventHandler(dev_OnPacketArrival); 48 | 49 | device.Open(new DeviceConfiguration { ReadTimeout = 500 }); 50 | 51 | Console.WriteLine(); 52 | Console.WriteLine("-- Listening on {0}, hit 'Enter' to stop...", 53 | device.Description); 54 | 55 | // Start the capturing process 56 | device.StartCapture(); 57 | 58 | // Wait for 'Enter' from the user. 59 | Console.ReadLine(); 60 | 61 | // Stop the capturing process 62 | device.StopCapture(); 63 | 64 | Console.WriteLine("-- Capture stopped."); 65 | 66 | // Print out the device statistics 67 | Console.WriteLine(device.Statistics.ToString()); 68 | } 69 | 70 | static void dev_OnPacketArrival(object sender, SharpPcap.PacketCapture e) 71 | { 72 | var time = e.Header.Timeval.Date; 73 | var len = e.Data.Length; 74 | var packet = e.GetPacket(); 75 | Console.WriteLine("{0}:{1}:{2},{3} Len={4}", 76 | time.Hour, time.Minute, time.Second, time.Millisecond, len); 77 | Console.WriteLine(packet.ToString()); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Examples/QueuingPacketsForBackgroundProcessing/QueuingPacketsForBackgroundProcessing.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/ReadingCaptureFile/Program.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | using System; 4 | using SharpPcap; 5 | using SharpPcap.LibPcap; 6 | using PacketDotNet; 7 | 8 | namespace ReadingCaptureFile 9 | { 10 | public class Program 11 | { 12 | public static void Main(string[] args) 13 | { 14 | var ver = Pcap.SharpPcapVersion; 15 | 16 | /* Print SharpPcap version */ 17 | Console.WriteLine("SharpPcap {0}, ReadingCaptureFile", ver); 18 | Console.WriteLine(); 19 | 20 | Console.WriteLine(); 21 | 22 | // read the file from stdin or from the command line arguments 23 | string capFile; 24 | if (args.Length == 0) 25 | { 26 | Console.Write("-- Please enter an input capture file name: "); 27 | capFile = Console.ReadLine(); 28 | } 29 | else 30 | { 31 | // use the first argument as the filename 32 | capFile = args[0]; 33 | } 34 | 35 | Console.WriteLine("opening '{0}'", capFile); 36 | 37 | ICaptureDevice device; 38 | 39 | try 40 | { 41 | // Get an offline device 42 | device = new CaptureFileReaderDevice(capFile); 43 | 44 | // Open the device 45 | device.Open(); 46 | } 47 | catch (Exception e) 48 | { 49 | Console.WriteLine("Caught exception when opening file" + e.ToString()); 50 | return; 51 | } 52 | 53 | // Register our handler function to the 'packet arrival' event 54 | device.OnPacketArrival += 55 | new PacketArrivalEventHandler(device_OnPacketArrival); 56 | 57 | Console.WriteLine(); 58 | Console.WriteLine 59 | ("-- Capturing from '{0}', hit 'Ctrl-C' to exit...", 60 | capFile); 61 | 62 | var startTime = DateTime.Now; 63 | 64 | // Start capture 'INFINTE' number of packets 65 | // This method will return when EOF reached. 66 | device.Capture(); 67 | 68 | // Close the pcap device 69 | device.Close(); 70 | var endTime = DateTime.Now; 71 | Console.WriteLine("-- End of file reached."); 72 | 73 | var duration = endTime - startTime; 74 | Console.WriteLine("Read {0} packets in {1}s", packetIndex, duration.TotalSeconds); 75 | 76 | Console.Write("Hit 'Enter' to exit..."); 77 | Console.ReadLine(); 78 | } 79 | 80 | private static int packetIndex = 0; 81 | 82 | /// 83 | /// Prints the source and dest MAC addresses of each received Ethernet frame 84 | /// 85 | private static void device_OnPacketArrival(object sender, PacketCapture e) 86 | { 87 | packetIndex++; 88 | 89 | var rawPacket = e.GetPacket(); 90 | var packet = PacketDotNet.Packet.ParsePacket(rawPacket.LinkLayerType, rawPacket.Data); 91 | 92 | var ethernetPacket = packet.Extract(); 93 | if (ethernetPacket != null) 94 | { 95 | Console.WriteLine("{0} At: {1}:{2}: MAC:{3} -> MAC:{4}", 96 | packetIndex, 97 | e.Header.Timeval.Date.ToString(), 98 | e.Header.Timeval.Date.Millisecond, 99 | ethernetPacket.SourceHardwareAddress, 100 | ethernetPacket.DestinationHardwareAddress); 101 | } 102 | } 103 | } 104 | } 105 | 106 | -------------------------------------------------------------------------------- /Examples/ReadingCaptureFile/ReadingCaptureFile.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/WakeOnLan/WakeOnLan.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Examples/WinformsExample/DeviceListForm.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | using System; 4 | using System.Windows.Forms; 5 | using SharpPcap; 6 | 7 | namespace WinformsExample 8 | { 9 | public partial class DeviceListForm : Form 10 | { 11 | public DeviceListForm() 12 | { 13 | InitializeComponent(); 14 | } 15 | 16 | private void DeviceListForm_Load(object sender, EventArgs e) 17 | { 18 | foreach (var dev in CaptureDeviceList.Instance) 19 | { 20 | var str = String.Format("{0} {1}", dev.Name, dev.Description); 21 | deviceList.Items.Add(str); 22 | } 23 | } 24 | 25 | public delegate void OnItemSelectedDelegate(int itemIndex); 26 | public event OnItemSelectedDelegate OnItemSelected; 27 | 28 | public delegate void OnCancelDelegate(); 29 | public event OnCancelDelegate OnCancel; 30 | 31 | private void buttonCancel_Click(object sender, EventArgs e) 32 | { 33 | OnCancel(); 34 | } 35 | 36 | private void buttonOk_Click(object sender, EventArgs e) 37 | { 38 | if (deviceList.SelectedItem != null) 39 | { 40 | OnItemSelected(deviceList.SelectedIndex); 41 | } 42 | } 43 | 44 | private void deviceList_MouseDoubleClick(object sender, MouseEventArgs e) 45 | { 46 | if (deviceList.SelectedItem != null) 47 | { 48 | OnItemSelected(deviceList.SelectedIndex); 49 | } 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /Examples/WinformsExample/Program.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | using System; 4 | using System.Windows.Forms; 5 | 6 | namespace WinformsExample 7 | { 8 | static class Program 9 | { 10 | /// 11 | /// The main entry point for the application. 12 | /// 13 | [STAThread] 14 | static void Main() 15 | { 16 | Application.EnableVisualStyles(); 17 | Application.SetCompatibleTextRenderingDefault(false); 18 | 19 | var mainCaptureForm = new CaptureForm(); 20 | Application.Run(mainCaptureForm); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Examples/WinformsExample/Resources/play_icon_enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotpcap/sharppcap/bfedf297e7410ffcf44e05d14f7fbef304f20895/Examples/WinformsExample/Resources/play_icon_enabled.png -------------------------------------------------------------------------------- /Examples/WinformsExample/Resources/stop_icon_disabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotpcap/sharppcap/bfedf297e7410ffcf44e05d14f7fbef304f20895/Examples/WinformsExample/Resources/stop_icon_disabled.png -------------------------------------------------------------------------------- /Examples/WinformsExample/Resources/stop_icon_enabled.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotpcap/sharppcap/bfedf297e7410ffcf44e05d14f7fbef304f20895/Examples/WinformsExample/Resources/stop_icon_enabled.png -------------------------------------------------------------------------------- /Examples/WinformsExample/WinformsExample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | WinExe 4 | net48 5 | true 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Examples/WinpkFilterExample/Program.cs: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: MIT 2 | 3 | using System; 4 | using PacketDotNet; 5 | using SharpPcap; 6 | using SharpPcap.WinpkFilter; 7 | 8 | namespace WinpkFilterExample 9 | { 10 | /// 11 | /// Example showing packet manipulation 12 | /// 13 | public class Program 14 | { 15 | static void Main() 16 | { 17 | var api = WinpkFilterDriver.Open(); 18 | if (api.Handle.IsInvalid) 19 | { 20 | throw new ApplicationException("Cannot load driver."); 21 | } 22 | foreach (var device in api.GetNetworkDevices()) 23 | { 24 | PassThruThread(device); 25 | } 26 | Console.ReadLine(); 27 | } 28 | 29 | private static void PassThruThread(WinpkFilterDevice device) 30 | { 31 | if (!device.IsValid) 32 | { 33 | Console.WriteLine($"Skipped {device.FriendlyName}."); 34 | return; 35 | } 36 | try 37 | { 38 | device.OnPacketArrival += Device_OnPacketArrival; 39 | device.AdapterMode = AdapterModes.Tunnel 40 | | AdapterModes.LoopbackFilter 41 | | AdapterModes.LoopbackBlock; 42 | 43 | device.StartCapture(); 44 | Console.WriteLine($"Added {device.FriendlyName}."); 45 | } 46 | catch (PcapException ex) 47 | { 48 | Console.WriteLine($"Failed {device.FriendlyName}: " + ex.Message); 49 | } 50 | } 51 | 52 | private static void Device_OnPacketArrival(object sender, PacketCapture e) 53 | { 54 | var device = (WinpkFilterDevice)sender; 55 | var packet = e.GetPacket().GetPacket(); 56 | if (packet.PayloadPacket is IPPacket ip) 57 | { 58 | Console.WriteLine(ip.ToString(StringOutputType.Colored)); 59 | } 60 | device.SendPacket(e.Data, e.Header); 61 | } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /Examples/WinpkFilterExample/WinpkFilterExample.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | Exe 4 | net8.0 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /History.md: -------------------------------------------------------------------------------- 1 | 2 | ## History 3 | 4 | Tamir Gal started the SharpPcap project around 2004\. He wanted to use WinPcap in a .NET application while working on his final project for university. The project involved analyzing and decoding VoIP traffic and he wanted to keep coding simple with C# which has time saving features like garbage collection. Accessing the WinPcap API from .NET seemed to be quite a popular requirement, and he found some useful projects on CodeProject's website that let you do just that. 5 | 6 | The projects available at the time did not lend themselves to being used to capture and analyze traffic. Some had mixed ui and capture code, others had reimplemented some of WinPcap's functions in C# and others lacked features such as offline file reading or source code. 7 | 8 | And so, Tamir decided to start his own library for the task. Several versions in the 1.x series were released. Development slowed towards mid-2007 when the last version in the 1.x series was released, SharpPcap 1.6.2. 9 | 10 | Chris Morgan took over development of SharpPcap in November of 2008\. Since then SharpPcap has had major internal rewrites and API improvements including Linux, Mac support. 11 | 12 | In late February 2010 SharpPcap v3.0 was released. This release represents a rewrite of SharpPcap's packet parsers. Packet parsing functionality was broken out into a new library, [Packet.Net](http://packetnet.sf.net). SharpPcap takes care of interfacing with libpcap/winpcap and Packet.Net takes care of packet dissection and creation. The details of Packet.Net's architecture will be discussed later in the turotial. 13 | 14 | SharpPcap v3.5 was released February 1st, 2011\. The 3.5 release contained significant API changes as well as WinPcap remote capture and AirPcap support. 15 | 16 | SharpPcap v4.0 was released September 13, 2011\. The 4.0 release contains significant performance improvements due to contributions from Michael Giagnocavo. SharpPcap 4.0 is >50% faster than the last revision, v3.7\. It also contains API cleanup for reading and writing to capture files in the form of new CaptureFileWriterDevice and CaptureFileReaderDevice that replaces an older and much more confusing way of writing to capture files and makes reading and writing analogous. 17 | 18 | SharpPcap v4.2 was released January 14th, 2013\. 4.2 adds support for IEEE 802.1Q vlan tags, corrects access modifiers in Packet to enable 3rd party assemblies to use this class and introduces Packet.Extract(). Packet.Extract() replaces per-packet GetEncapsulated() methods, now deprecated, with a single high level routine that is a part of the base class of all captured packets. 19 | 20 | -------------------------------------------------------------------------------- /LICENSES/MIT.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Tamir Gal, Chris Morgan, Ayoub Kaanich, Noah Potash, Phillip Lemon, Evan Plaice 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /REUSE.toml: -------------------------------------------------------------------------------- 1 | # Copyright 2023-2024 Ayoub Kaanich 2 | # SPDX-License-Identifier: MIT 3 | version = 1 4 | SPDX-PackageName = "sharppcap" 5 | SPDX-PackageSupplier = "Chris Morgan " 6 | SPDX-PackageDownloadLocation = "https://github.com/dotpcap/sharppcap" 7 | 8 | [[annotations]] 9 | path = [ 10 | "Examples/**", 11 | "SharpPcap.sln", 12 | "Test/capture_files/10k_packets.pcap", 13 | "Test/capture_files/arp_request_response.pcap", 14 | "Test/capture_files/ipv6_http.pcap", 15 | "Test/capture_files/ipv6_icmpv6_packet.pcap", 16 | "Test/capture_files/ip_packet_bogus_length.pcap", 17 | "Test/capture_files/README", 18 | "Test/capture_files/tcp.pcap", 19 | "Test/capture_files/tcp_with_extra_bytes.pcap", 20 | "Test/capture_files/test_stream.pcap", 21 | "Test/capture_files/udp_dns_request_response.pcap", 22 | ] 23 | precedence = "aggregate" 24 | SPDX-FileCopyrightText = [ 25 | "Tamir Gal ", 26 | "Chris Morgan ", 27 | ] 28 | SPDX-License-Identifier = "MIT" 29 | 30 | [[annotations]] 31 | path = ["Tutorial/**", "History.md", "README.md", "renovate.json"] 32 | precedence = "aggregate" 33 | SPDX-FileCopyrightText = "Chris Morgan " 34 | SPDX-License-Identifier = "MIT" 35 | 36 | [[annotations]] 37 | path = "Test/capture_files/arp_with_vlan.pcap" 38 | precedence = "aggregate" 39 | SPDX-FileCopyrightText = "Houcem Benali " 40 | SPDX-License-Identifier = "MIT" 41 | -------------------------------------------------------------------------------- /SharpPcap/AuthenticationTypes.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2010-2011 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | namespace SharpPcap 6 | { 7 | /// 8 | /// Types of authentication 9 | /// 10 | public enum AuthenticationTypes 11 | { 12 | /// 13 | /// Null authentication 14 | /// 15 | Null = 0, 16 | 17 | /// 18 | /// Username/password authentication 19 | /// 20 | Password = 1 21 | } 22 | } 23 | 24 | -------------------------------------------------------------------------------- /SharpPcap/CaptureDeviceExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chris Morgan 2 | // Copyright 2021 Ayoub Kaanich 3 | // SPDX-License-Identifier: MIT 4 | 5 | using PacketDotNet; 6 | using SharpPcap.LibPcap; 7 | using System; 8 | 9 | namespace SharpPcap 10 | { 11 | public static class CaptureDeviceExtensions 12 | { 13 | /// 14 | /// Defined as extension method for easier migration, since this is the most used form of Open in SharpPcap 5.x 15 | /// 16 | /// 17 | /// 18 | /// 19 | public static void Open(this IPcapDevice device, DeviceModes mode = DeviceModes.None, int read_timeout = 1000) 20 | { 21 | var configuration = new DeviceConfiguration() 22 | { 23 | Mode = mode, 24 | ReadTimeout = read_timeout, 25 | }; 26 | device.Open(configuration); 27 | } 28 | 29 | public static void Open(this CaptureFileWriterDevice device, ICaptureDevice captureDevice) 30 | { 31 | var configuration = new DeviceConfiguration() 32 | { 33 | LinkLayerType = captureDevice.LinkType, 34 | }; 35 | device.Open(configuration); 36 | } 37 | 38 | public static void Open(this CaptureFileWriterDevice device, LinkLayers linkLayerType = LinkLayers.Ethernet) 39 | { 40 | var configuration = new DeviceConfiguration() 41 | { 42 | LinkLayerType = linkLayerType, 43 | }; 44 | device.Open(configuration); 45 | } 46 | 47 | /// 48 | /// Sends a raw packet through this device 49 | /// 50 | /// The packet bytes to send 51 | /// The number of bytes to send 52 | public static void SendPacket(this IInjectionDevice device, byte[] p, int size) 53 | { 54 | device.SendPacket(new ReadOnlySpan(p, 0, size)); 55 | } 56 | 57 | /// 58 | /// Sends a raw packet through this device 59 | /// 60 | /// The packet to send 61 | public static void SendPacket(this IInjectionDevice device, Packet p) 62 | { 63 | device.SendPacket(p.Bytes); 64 | } 65 | 66 | /// 67 | /// Sends a raw packet through this device 68 | /// 69 | /// The packet to send 70 | /// The number of bytes to send 71 | public static void SendPacket(this IInjectionDevice device, Packet p, int size) 72 | { 73 | device.SendPacket(p.Bytes, size); 74 | } 75 | 76 | /// 77 | /// Send a raw packet through this device 78 | /// 79 | /// 80 | /// 81 | /// 82 | public static void SendPacket(this IInjectionDevice device, RawCapture p, ICaptureHeader? header = null) 83 | { 84 | device.SendPacket(new ReadOnlySpan(p.Data), header); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /SharpPcap/CaptureDeviceList.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Collections.ObjectModel; 8 | 9 | namespace SharpPcap 10 | { 11 | /// 12 | /// List of available capture devices 13 | /// 14 | public class CaptureDeviceList : ReadOnlyCollection 15 | { 16 | private static CaptureDeviceList? instance; 17 | 18 | private LibPcap.LibPcapLiveDeviceList libPcapDeviceList; 19 | 20 | /// 21 | /// Method to retrieve this classes singleton instance 22 | /// 23 | public static CaptureDeviceList Instance 24 | { 25 | get 26 | { 27 | if (instance == null) 28 | { 29 | instance = new CaptureDeviceList(); 30 | } 31 | 32 | return instance; 33 | } 34 | } 35 | 36 | /// 37 | /// Caution: Use the singlton instance unless you know why you need to call this. 38 | /// One use is for multiple filters on the same physical device. To apply multiple 39 | /// filters open the same physical device multiple times, one for each 40 | /// filter by calling this routine and picking the same device out of each list. 41 | /// 42 | /// 43 | /// A 44 | /// 45 | public static CaptureDeviceList New() 46 | { 47 | var newCaptureDevice = new CaptureDeviceList(); 48 | 49 | newCaptureDevice.libPcapDeviceList = LibPcap.LibPcapLiveDeviceList.New(); 50 | 51 | // refresh the device list to flush the original devices and pull the 52 | // new ones into the newCaptureDevice 53 | newCaptureDevice.Refresh(); 54 | 55 | return newCaptureDevice; 56 | } 57 | 58 | /// 59 | /// Represents a strongly typed, read-only list of PcapDevices. 60 | /// 61 | private CaptureDeviceList() 62 | : base(new List()) 63 | { 64 | libPcapDeviceList = LibPcap.LibPcapLiveDeviceList.Instance; 65 | Refresh(); 66 | } 67 | 68 | /// 69 | /// Refresh the device list 70 | /// 71 | public void Refresh() 72 | { 73 | lock (this) 74 | { 75 | // clear out any items we might have 76 | base.Items.Clear(); 77 | libPcapDeviceList.Refresh(); 78 | 79 | foreach (var i in libPcapDeviceList) 80 | { 81 | base.Items.Add(i); 82 | } 83 | } 84 | } 85 | 86 | #region Device Indexers 87 | /// The name or description of the pcap interface to get. 88 | public ILiveDevice this[string Name] 89 | { 90 | get 91 | { 92 | // lock to prevent issues with multi-threaded access 93 | // with other methods 94 | lock (this) 95 | { 96 | return libPcapDeviceList[Name]; 97 | } 98 | } 99 | } 100 | 101 | #endregion 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /SharpPcap/CaptureStoppedEventHandler.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2005 Tamir Gal 2 | // Copyright 2009-2010 Chris Morgan 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | namespace SharpPcap 7 | { 8 | /// 9 | /// A delegate for notifying of a capture stopped event 10 | /// 11 | public delegate void CaptureStoppedEventHandler(object sender, CaptureStoppedEventStatus status); 12 | } 13 | -------------------------------------------------------------------------------- /SharpPcap/CaptureStoppedEventStatus.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | namespace SharpPcap 6 | { 7 | /// 8 | /// Status types when capture is stopped 9 | /// 10 | public enum CaptureStoppedEventStatus 11 | { 12 | /// 13 | /// Capture completed without errors 14 | /// 15 | CompletedWithoutError, 16 | 17 | /// 18 | /// Error while capturing 19 | /// 20 | ErrorWhileCapturing 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SharpPcap/DeviceConfiguration.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | 7 | namespace SharpPcap 8 | { 9 | public class DeviceConfiguration 10 | { 11 | /// 12 | /// Defines if the adapter mode. 13 | /// 14 | public DeviceModes Mode { get; set; } 15 | 16 | public int ReadTimeout { get; set; } = 1000; 17 | 18 | // MAX_PACKET_SIZE (65536) grants that the whole packet will be captured on all the MACs. 19 | public int Snaplen { get; set; } = Pcap.MAX_PACKET_SIZE; 20 | 21 | public MonitorMode? Monitor { get; set; } 22 | 23 | public int? BufferSize { get; set; } 24 | 25 | public int? KernelBufferSize { get; set; } 26 | 27 | public RemoteAuthentication? Credentials { get; set; } 28 | 29 | public bool? Immediate { get; set; } 30 | 31 | public int? MinToCopy { get; set; } 32 | 33 | #region File IO 34 | /// 35 | /// Writing capture files 36 | /// 37 | public PacketDotNet.LinkLayers LinkLayerType { get; set; } 38 | #endregion 39 | 40 | public TimestampResolution? TimestampResolution { get; set; } 41 | 42 | public TimestampType? TimestampType { get; set; } 43 | 44 | public event EventHandler? ConfigurationFailed; 45 | 46 | internal void RaiseConfigurationFailed(string property, PcapError error, string message) 47 | { 48 | message = message ?? $"Failed to set {property}."; 49 | 50 | if (ConfigurationFailed is null) 51 | { 52 | var exception = error == PcapError.PlatformNotSupported ? 53 | (Exception)new PlatformNotSupportedException() : 54 | new PcapException(message, error); 55 | throw exception; 56 | } 57 | else 58 | { 59 | var args = new ConfigurationFailedEventArgs 60 | { 61 | Property = property, 62 | Error = error, 63 | Message = message, 64 | }; 65 | ConfigurationFailed.Invoke(this, args); 66 | } 67 | } 68 | } 69 | 70 | public class ConfigurationFailedEventArgs : EventArgs 71 | { 72 | public PcapError Error { get; internal init; } 73 | public required string Property { get; init; } 74 | public required string Message { get; init; } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /SharpPcap/DeviceModes.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | 7 | namespace SharpPcap 8 | { 9 | /// 10 | /// The mode used when opening a device 11 | /// See pcap_open() documentation 12 | /// https://github.com/the-tcpdump-group/libpcap/blob/aa818d3fe5add3f69b87671fc17f8eeb09f10139/pcap/pcap.h#L938 13 | /// 14 | [Flags] 15 | public enum DeviceModes : short 16 | { 17 | /// 18 | /// No flags set 19 | /// 20 | None = 0, 21 | 22 | /// 23 | /// Defines if the adapter has to go in promiscuous mode. 24 | /// 25 | Promiscuous = 1, 26 | 27 | /// 28 | /// Defines if the data trasfer (in case of a remote capture) 29 | /// has to be done with UDP protocol. 30 | /// 31 | DataTransferUdp = 2, 32 | 33 | /// 34 | /// Defines if the remote probe will capture its own generated traffic. 35 | /// 36 | NoCaptureRemote = 4, 37 | 38 | /// 39 | /// Defines if the local adapter will capture its own generated traffic. 40 | /// 41 | NoCaptureLocal = 8, 42 | 43 | /// 44 | /// This flag configures the adapter for maximum responsiveness. 45 | /// 46 | MaxResponsiveness = 16 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /SharpPcap/DeviceNotReadyException.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2005 Tamir Gal 2 | // Copyright 2008-2010 Chris Morgan 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | namespace SharpPcap 7 | { 8 | /// 9 | /// A PcapDevice or dumpfile is not ready for capture operations. 10 | /// 11 | public class DeviceNotReadyException : PcapException 12 | { 13 | internal DeviceNotReadyException() : base() 14 | { 15 | } 16 | 17 | internal DeviceNotReadyException(string msg) : base(msg) 18 | { 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SharpPcap/GetPacketStatus.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | namespace SharpPcap 6 | { 7 | /// 8 | /// See https://www.tcpdump.org/manpages/pcap_next_ex.3pcap.html 9 | /// and https://github.com/the-tcpdump-group/libpcap/blob/fbcc461fbc2bd3b98de401cc04e6a4a10614e99f/pcap/pcap.h 10 | /// 11 | public enum GetPacketStatus 12 | { 13 | ReadTimeout = 0, 14 | 15 | PacketRead = 1, 16 | 17 | /// 18 | /// PCAP_ERROR 19 | /// 20 | Error = -1, 21 | 22 | /// 23 | /// PCAP_ERROR_BREAK 24 | /// 25 | NoRemainingPackets = -2, 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /SharpPcap/ICaptureDevice.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | namespace SharpPcap 7 | { 8 | /// 9 | /// Interfaces for capture devices 10 | /// 11 | public interface ICaptureDevice : IPcapDevice 12 | { 13 | 14 | #region Capture methods and properties 15 | /// 16 | /// Fires whenever a new packet is processed, either when the packet arrives 17 | /// from the network device or when the packet is read from the on-disk file.
18 | /// For network captured packets this event is invoked only when working in "PcapMode.Capture" mode. 19 | ///
20 | event PacketArrivalEventHandler OnPacketArrival; 21 | 22 | /// 23 | /// Fired when the capture process of this pcap device is stopped 24 | /// 25 | event CaptureStoppedEventHandler OnCaptureStopped; 26 | 27 | /// 28 | /// Return a value indicating if the capturing process of this adapter is started 29 | /// 30 | bool Started { get; } 31 | 32 | /// 33 | /// Maximum time within which the capture thread must join the main thread (on 34 | /// ) or else the thread is aborted and an exception thrown. 35 | /// 36 | TimeSpan StopCaptureTimeout { get; set; } 37 | 38 | /// 39 | /// Start the capture 40 | /// 41 | void StartCapture(); 42 | 43 | /// 44 | /// Stop the capture 45 | /// 46 | void StopCapture(); 47 | 48 | /// 49 | /// Synchronously capture packets on this device. Method blocks forever. 50 | /// 51 | void Capture(); 52 | 53 | #endregion 54 | 55 | /// 56 | /// Retrieves the next packet from a device 57 | /// 58 | /// 59 | /// Status of the operation 60 | GetPacketStatus GetNextPacket(out PacketCapture e); 61 | 62 | /// 63 | /// Retrieves pcap statistics 64 | /// 65 | /// Devices that lack statistics support return null 66 | /// 67 | ICaptureStatistics? Statistics { get; } 68 | 69 | #region Timestamp 70 | /// 71 | /// Note: libpcap docs and code use the term 'precision' and 'resolution'. We use the term 72 | /// 'resolution' as it more closely reflects this setting 73 | /// 74 | /// Note: It isn't possible to set the resolution on a device that has already 75 | /// been activated. Please Open() the device with the desired resolution. 76 | /// 77 | TimestampResolution TimestampResolution { get; } 78 | #endregion 79 | } 80 | } 81 | 82 | -------------------------------------------------------------------------------- /SharpPcap/ICaptureHeader.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | namespace SharpPcap 5 | { 6 | /// 7 | /// Information common to all captured packets 8 | /// 9 | public interface ICaptureHeader 10 | { 11 | /// 12 | /// Timestamp of this header instance 13 | /// 14 | PosixTimeval Timeval { get; } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SharpPcap/ICaptureStatistics.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | namespace SharpPcap 6 | { 7 | /// 8 | /// Adapter statistics, received, dropped packet counts etc 9 | /// 10 | public interface ICaptureStatistics 11 | { 12 | /// 13 | /// Number of packets received 14 | /// 15 | uint ReceivedPackets { get; set; } 16 | 17 | /// 18 | /// Number of packets dropped 19 | /// 20 | uint DroppedPackets { get; set; } 21 | 22 | /// 23 | /// Number of interface dropped packets 24 | /// 25 | uint InterfaceDroppedPackets { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SharpPcap/IInjectionDevice.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | namespace SharpPcap 7 | { 8 | public interface IInjectionDevice : IPcapDevice 9 | { 10 | /// 11 | /// Sends a raw packet through this device 12 | /// 13 | /// The packet bytes to send 14 | /// The number of bytes to send 15 | void SendPacket(ReadOnlySpan p, ICaptureHeader? header = null); 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /SharpPcap/ILiveDevice.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | namespace SharpPcap 6 | { 7 | /// 8 | /// Live device, capable of both capture and injection 9 | /// 10 | public interface ILiveDevice : ICaptureDevice , IInjectionDevice 11 | { 12 | 13 | } 14 | } 15 | 16 | -------------------------------------------------------------------------------- /SharpPcap/IPcapDevice.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | namespace SharpPcap 7 | { 8 | /// 9 | /// Base interface for live and file devices 10 | /// 11 | public interface IPcapDevice : IDisposable 12 | { 13 | /// 14 | /// Gets the name of the device 15 | /// 16 | string Name { get; } 17 | 18 | /// 19 | /// Description of the device 20 | /// 21 | string Description { get; } 22 | 23 | /// 24 | /// The last pcap error associated with this pcap device 25 | /// 26 | string? LastError { get; } 27 | 28 | /// 29 | /// Kernel level filtering expression associated with this device. 30 | /// For more info on filter expression syntax, see: 31 | /// https://www.winpcap.org/docs/docs_412/html/group__language.html 32 | /// 33 | string? Filter { get; set; } 34 | 35 | /// 36 | /// Mac address of the physical device 37 | /// 38 | System.Net.NetworkInformation.PhysicalAddress? MacAddress { get; } 39 | 40 | /// 41 | /// Open the device. To start capturing call the 'StartCapture' function 42 | /// 43 | /// 44 | /// A 45 | /// 46 | void Open(DeviceConfiguration configuration); 47 | 48 | /// 49 | /// Closes this adapter 50 | /// 51 | void Close(); 52 | 53 | /// 54 | /// Return the pcap link layer value of an adapter. 55 | /// 56 | PacketDotNet.LinkLayers LinkType { get; } 57 | } 58 | } 59 | 60 | -------------------------------------------------------------------------------- /SharpPcap/InvalidOperationDuringBackgroundCaptureException.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | namespace SharpPcap 6 | { 7 | /// 8 | /// Thrown when an operation can't be performed because 9 | /// a background capture has been started via PcapDevice.StartCapture() 10 | /// 11 | public class InvalidOperationDuringBackgroundCaptureException : PcapException 12 | { 13 | /// 14 | /// string constructor 15 | /// 16 | /// 17 | /// A 18 | /// 19 | public InvalidOperationDuringBackgroundCaptureException(string msg) : base(msg) 20 | { 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /SharpPcap/LibPcap/CaptureFileReaderDevice.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using System.Text; 7 | using System.IO; 8 | 9 | namespace SharpPcap.LibPcap 10 | { 11 | /// 12 | /// Read a pcap capture file 13 | /// 14 | public class CaptureFileReaderDevice : CaptureReaderDevice 15 | { 16 | private readonly string m_pcapFile; 17 | 18 | /// 19 | /// The name of the capture file 20 | /// 21 | public override string Name 22 | { 23 | get 24 | { 25 | return m_pcapFile; 26 | } 27 | } 28 | 29 | /// 30 | /// Description of the device 31 | /// 32 | public override string Description 33 | { 34 | get 35 | { 36 | return "Capture file reader device"; 37 | } 38 | } 39 | 40 | /// 41 | /// Number of bytes in the capture file 42 | /// 43 | public long FileSize 44 | { 45 | get 46 | { 47 | return new FileInfo(Name).Length; 48 | } 49 | } 50 | 51 | /// 52 | /// The underlying pcap file name 53 | /// 54 | public string FileName 55 | { 56 | get { return System.IO.Path.GetFileName(this.Name); } 57 | } 58 | 59 | /// 60 | /// 61 | /// 62 | /// 63 | /// A 64 | /// 65 | public CaptureFileReaderDevice(string captureFilename) 66 | { 67 | m_pcapFile = captureFilename; 68 | } 69 | 70 | /// 71 | /// Open the device 72 | /// 73 | public override void Open(DeviceConfiguration configuration) 74 | { 75 | ErrorBuffer errbuf; //will hold errors 76 | 77 | PcapHandle adapterHandle; 78 | 79 | // Check if we need to open with a defined precision 80 | var has_offline_with_tstamp_precision_support = Pcap.LibpcapVersion >= new Version(1, 5, 1); 81 | var resolution = configuration.TimestampResolution ?? TimestampResolution.Microsecond; 82 | if (has_offline_with_tstamp_precision_support) 83 | { 84 | adapterHandle = LibPcapSafeNativeMethods.pcap_open_offline_with_tstamp_precision(m_pcapFile, (uint)resolution, out errbuf); 85 | } 86 | else 87 | { 88 | // notify the user that they asked for a non-standard resolution but their libpcap 89 | // version lacks the necessary function 90 | if (resolution != TimestampResolution.Microsecond) 91 | { 92 | configuration.RaiseConfigurationFailed( 93 | nameof(configuration.TimestampResolution), 94 | PcapError.PlatformNotSupported, 95 | "pcap version is < 1.5.1, needs pcap_open_offline_with_tstamp_precision()" 96 | ); 97 | } 98 | 99 | adapterHandle = LibPcapSafeNativeMethods.pcap_open_offline(m_pcapFile, out errbuf); 100 | } 101 | 102 | // handle error 103 | if (adapterHandle.IsInvalid) 104 | { 105 | string err = "Unable to open offline adapter: " + errbuf.ToString(); 106 | throw new PcapException(err); 107 | } 108 | 109 | // set the device handle 110 | Handle = adapterHandle; 111 | 112 | base.Open(configuration); 113 | } 114 | } 115 | } 116 | 117 | -------------------------------------------------------------------------------- /SharpPcap/LibPcap/CaptureHandleReaderDevice.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Hendrik Eckardt 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | using System.Runtime.InteropServices; 6 | using System.Text; 7 | 8 | namespace SharpPcap.LibPcap 9 | { 10 | /// 11 | /// Read a pcap capture from a file handle (e.g., a pipe). 12 | /// 13 | /// NOTE: libpcap will take ownership of the handle. The handle will be closed when this device is closed. 14 | /// On non-Windows systems, the handle passed to this class MUST be opened by fopen or similar functions 15 | /// that return a FILE* (e.g., via Mono.Posix.NETStandard). 16 | /// 17 | public class CaptureHandleReaderDevice : CaptureReaderDevice 18 | { 19 | /// 20 | /// File handle the object was created with. 21 | /// 22 | public SafeHandle FileHandle { get; } 23 | 24 | /// 25 | /// The name of the capture file. 26 | /// 27 | public override string Name => ""; 28 | 29 | /// 30 | /// Description of the device. 31 | /// 32 | public override string Description => "Capture handle reader device"; 33 | 34 | /// 35 | /// Creates a new CaptureHandleReaderDevice. 36 | /// 37 | /// 38 | /// On Windows, a native Windows handle. On other systems, a pointer to a C runtime FILE object. 39 | /// 40 | public CaptureHandleReaderDevice(SafeHandle handle) 41 | { 42 | FileHandle = handle; 43 | } 44 | 45 | /// 46 | /// Opens the device. 47 | /// 48 | public override void Open(DeviceConfiguration configuration) 49 | { 50 | // holds errors 51 | ErrorBuffer errbuf; 52 | 53 | var resolution = configuration.TimestampResolution ?? TimestampResolution.Microsecond; 54 | PcapHandle adapterHandle; 55 | try 56 | { 57 | adapterHandle = LibPcapSafeNativeMethods.pcap_open_handle_offline_with_tstamp_precision( 58 | FileHandle, (uint)resolution, out errbuf); 59 | } 60 | catch (TypeLoadException ex) 61 | { 62 | throw new NotSupportedException("libpcap 1.5.0 or higher is required for opening captures by handle", ex); 63 | } 64 | 65 | // handle error 66 | if (adapterHandle.IsInvalid) 67 | { 68 | string err = "Unable to open offline adapter: " + errbuf; 69 | throw new PcapException(err); 70 | } 71 | 72 | // set the device handle 73 | Handle = adapterHandle; 74 | 75 | base.Open(configuration); 76 | } 77 | } 78 | } 79 | 80 | -------------------------------------------------------------------------------- /SharpPcap/LibPcap/CaptureReaderDevice.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Hendrik Eckardt 2 | // SPDX-License-Identifier: MIT 3 | 4 | namespace SharpPcap.LibPcap 5 | { 6 | /// 7 | /// Base class for 'offline' devices. 8 | /// 9 | public abstract class CaptureReaderDevice : PcapDevice 10 | { 11 | protected CaptureReaderDevice() 12 | : base(null) 13 | { 14 | } 15 | 16 | /// 17 | /// Retrieves pcap statistics. 18 | /// 19 | /// Not supported for this device. 20 | /// 21 | /// 22 | /// A 23 | /// 24 | public override ICaptureStatistics? Statistics => null; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SharpPcap/LibPcap/LibPcapSafeNativeMethods.Resolver.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.IO; 8 | using System.Reflection; 9 | using System.Runtime.InteropServices; 10 | using System.Text; 11 | 12 | namespace SharpPcap.LibPcap 13 | { 14 | /// 15 | /// Per http://msdn.microsoft.com/en-us/ms182161.aspx 16 | /// 17 | internal static partial class LibPcapSafeNativeMethods 18 | { 19 | 20 | [DllImport("kernel32.dll", CharSet = CharSet.Unicode, SetLastError = true)] 21 | [return: MarshalAs(UnmanagedType.Bool)] 22 | static extern bool SetDllDirectory(string lpPathName); 23 | 24 | static LibPcapSafeNativeMethods() 25 | { 26 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 27 | { 28 | SetDllDirectory(Path.Combine(Environment.SystemDirectory, "Npcap")); 29 | } 30 | else 31 | { 32 | RegisterResolver(); 33 | } 34 | StringEncoding = ConfigureStringEncoding(); 35 | } 36 | 37 | /// 38 | /// The class NativeLibrary is only available since .NET Core 3.0 39 | /// It's not available in .NET Framework, 40 | /// but that does not affect us since we would use the Windows dll name wpcap 41 | /// 42 | private static void RegisterResolver() 43 | { 44 | NativeLibrary.SetDllImportResolver(typeof(LibPcapSafeNativeMethods).Assembly, Resolver); 45 | } 46 | 47 | public static IntPtr Resolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath) 48 | { 49 | if (libraryName != PCAP_DLL) 50 | { 51 | // Use default resolver 52 | return IntPtr.Zero; 53 | } 54 | 55 | var names = new List(); 56 | 57 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 58 | { 59 | names.Add("libpcap.so"); 60 | names.Add("libpcap.so.0"); 61 | names.Add("libpcap.so.0.8"); 62 | names.Add("libpcap.so.1"); 63 | } 64 | 65 | if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) 66 | { 67 | names.Add("libpcap.dylib"); 68 | } 69 | 70 | foreach (var name in names) 71 | { 72 | if (NativeLibrary.TryLoad(name, out var handle)) 73 | { 74 | return handle; 75 | } 76 | } 77 | 78 | return IntPtr.Zero; 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /SharpPcap/LibPcap/NativeLibrary.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Ayoub Kaanich 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | using System.Reflection; 6 | using System.Runtime.InteropServices; 7 | 8 | #if !NET8_0_OR_GREATER 9 | namespace SharpPcap.LibPcap 10 | { 11 | /** 12 | * Helper class that uses reflection to access System.Runtime.InteropServices.NativeLibrary 13 | * This is needed in order to keep netstandard compatiblity 14 | * 15 | * We compile two variants of the DLL, one trimmable but requires .NET 8 thus have NativeLibrary available directly 16 | * and one that uses .NET standard, with no trimming support 17 | * 18 | */ 19 | class NativeLibrary 20 | { 21 | 22 | public delegate IntPtr DllImportResolver(string libraryName, Assembly assembly, DllImportSearchPath? searchPath); 23 | 24 | private static readonly Type NativeLibraryType; 25 | static NativeLibrary() 26 | { 27 | NativeLibraryType = typeof(DllImportSearchPath).Assembly 28 | .GetType("System.Runtime.InteropServices.NativeLibrary"); 29 | } 30 | 31 | public static void SetDllImportResolver(Assembly assembly, DllImportResolver resolver) 32 | { 33 | if (NativeLibraryType == null) 34 | { 35 | return; 36 | } 37 | 38 | var dllImportResolverType = typeof(DllImportSearchPath).Assembly 39 | .GetType("System.Runtime.InteropServices.DllImportResolver"); 40 | 41 | var setDllImportResolverMethod = NativeLibraryType 42 | .GetMethod( 43 | "SetDllImportResolver", 44 | BindingFlags.Public | BindingFlags.Static, 45 | null, 46 | new[] { typeof(Assembly), dllImportResolverType }, 47 | null 48 | ); 49 | 50 | setDllImportResolverMethod.Invoke(null, new object[] { 51 | assembly, 52 | Delegate.CreateDelegate(dllImportResolverType, resolver, "Invoke") 53 | }); 54 | } 55 | 56 | public static bool TryLoad(string libraryPath, out IntPtr handle) 57 | { 58 | var tryLoadMethod = NativeLibraryType 59 | ?.GetMethod( 60 | "TryLoad", 61 | BindingFlags.Public | BindingFlags.Static, 62 | null, 63 | new[] { typeof(string), typeof(IntPtr).MakeByRefType() }, 64 | null 65 | ); 66 | if (tryLoadMethod == null) 67 | { 68 | handle = IntPtr.Zero; 69 | return false; 70 | } 71 | var args = new object[] { libraryPath, IntPtr.Zero }; 72 | var res = (bool)tryLoadMethod.Invoke(null, args); 73 | handle = (IntPtr)args[1]; 74 | return res; 75 | } 76 | } 77 | } 78 | #endif -------------------------------------------------------------------------------- /SharpPcap/LibPcap/PcapAddress.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2005 Tamir Gal 2 | // Copyright 2009 Chris Morgan 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | using System; 7 | using System.Text; 8 | 9 | namespace SharpPcap.LibPcap 10 | { 11 | /// 12 | /// Managed representation of the unmanaged pcap_addr structure 13 | /// 14 | public class PcapAddress 15 | { 16 | /// 17 | /// The address value of this PcapAddress, null if none is present 18 | /// 19 | public Sockaddr? Addr { get; internal set; } 20 | 21 | /// 22 | /// Netmask of this PcapAddress, null if none is present 23 | /// 24 | public Sockaddr? Netmask { get; internal set; } 25 | 26 | /// 27 | /// Broadcast address of this PcapAddress, null if none is present 28 | /// 29 | public Sockaddr? Broadaddr { get; internal set; } 30 | 31 | /// 32 | /// Destination address, null if the interface isn't a point-to-point interface 33 | /// 34 | public Sockaddr? Dstaddr { get; internal set; } 35 | 36 | internal PcapAddress() 37 | { } 38 | 39 | internal PcapAddress(PcapUnmanagedStructures.pcap_addr pcap_addr) 40 | { 41 | if (pcap_addr.Addr != IntPtr.Zero) 42 | Addr = new Sockaddr(pcap_addr.Addr); 43 | if (pcap_addr.Netmask != IntPtr.Zero) 44 | Netmask = new Sockaddr(pcap_addr.Netmask); 45 | if (pcap_addr.Broadaddr != IntPtr.Zero) 46 | Broadaddr = new Sockaddr(pcap_addr.Broadaddr); 47 | if (pcap_addr.Dstaddr != IntPtr.Zero) 48 | Dstaddr = new Sockaddr(pcap_addr.Dstaddr); 49 | } 50 | 51 | /// 52 | /// ToString override 53 | /// 54 | /// 55 | /// A 56 | /// 57 | public override string ToString() 58 | { 59 | StringBuilder sb = new StringBuilder(); 60 | 61 | if (Addr != null) 62 | sb.AppendFormat("Addr: {0}\n", Addr.ToString()); 63 | 64 | if (Netmask != null) 65 | sb.AppendFormat("Netmask: {0}\n", Netmask.ToString()); 66 | 67 | if (Broadaddr != null) 68 | sb.AppendFormat("Broadaddr: {0}\n", Broadaddr.ToString()); 69 | 70 | if (Dstaddr != null) 71 | sb.AppendFormat("Dstaddr: {0}\n", Dstaddr.ToString()); 72 | 73 | return sb.ToString(); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /SharpPcap/LibPcap/PcapHandle.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Chris Morgan 2 | // Copyright 2021 Ayoub Kaanich 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | using Microsoft.Win32.SafeHandles; 7 | using System; 8 | using System.Runtime.InteropServices; 9 | 10 | namespace SharpPcap.LibPcap 11 | { 12 | public class PcapHandle : SafeHandleZeroOrMinusOneIsInvalid 13 | { 14 | public PcapHandle() 15 | : base(true) 16 | { 17 | } 18 | 19 | private PcapHandle(IntPtr handle) 20 | : base(true) 21 | { 22 | SetHandle(handle); 23 | } 24 | 25 | protected override bool ReleaseHandle() 26 | { 27 | LibPcapSafeNativeMethods.pcap_close(handle); 28 | return true; 29 | } 30 | 31 | internal static readonly PcapHandle Invalid = new PcapHandle(IntPtr.Zero); 32 | } 33 | 34 | /// 35 | /// Wrapper class that maintains reference to both pcap handle and file handle 36 | /// 37 | internal class PcapFileHandle : PcapHandle 38 | { 39 | private readonly SafeHandle FileHandle; 40 | 41 | public PcapFileHandle(IntPtr pcapHandle, SafeHandle fileHandle) 42 | { 43 | bool gotRef = false; 44 | // The file handle must not be closed by the runtime until the pcap handle is also closed 45 | // Incrementing the ref count ensure this 46 | fileHandle.DangerousAddRef(ref gotRef); 47 | FileHandle = gotRef ? fileHandle : new SafeFileHandle(IntPtr.Zero, false); 48 | SetHandle(pcapHandle); 49 | } 50 | 51 | // If somehow the file handle became invalid, the pcap handle will also be invalid 52 | public override bool IsInvalid => base.IsInvalid || FileHandle.IsInvalid; 53 | 54 | protected override bool ReleaseHandle() 55 | { 56 | // Closing the pcap handle will also close the file handle 57 | FileHandle.SetHandleAsInvalid(); 58 | return base.ReleaseHandle(); 59 | } 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /SharpPcap/LibPcap/SendQueueTransmitModes.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | namespace SharpPcap.LibPcap 6 | { 7 | /// 8 | /// The types of transmit modes allowed by the Npcap specific send queue 9 | /// implementation 10 | /// 11 | public enum SendQueueTransmitModes 12 | { 13 | /// 14 | /// Packets are sent as fast as possible 15 | /// 16 | Normal, 17 | 18 | /// 19 | /// Packets are synchronized in the kernel with a high precision timestamp 20 | /// 21 | Synchronized 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /SharpPcap/LibPcap/WindowsNativeMethods.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Ayoub Kaanich 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | using System.Runtime.InteropServices; 6 | using System.Security; 7 | using System.Text; 8 | 9 | namespace SharpPcap.LibPcap 10 | { 11 | [SuppressUnmanagedCodeSecurity] 12 | static class WindowsNativeMethods 13 | { 14 | 15 | /// 16 | /// https://docs.microsoft.com/en-us/windows/win32/api/netioapi/nf-netioapi-convertinterfaceguidtoluid 17 | /// 18 | /// 19 | /// 20 | /// 21 | [DllImport("Iphlpapi.dll")] 22 | private static extern uint ConvertInterfaceGuidToLuid(ref Guid InterfaceGuid, out ulong InterfaceLuid); 23 | 24 | 25 | /// 26 | /// https://docs.microsoft.com/en-us/windows/win32/api/netioapi/nf-netioapi-convertinterfaceluidtoalias 27 | /// 28 | /// 29 | /// 30 | /// 31 | /// 32 | [DllImport("Iphlpapi.dll")] 33 | private static extern uint ConvertInterfaceLuidToAlias( 34 | ref ulong InterfaceLuid, 35 | [MarshalAs(UnmanagedType.LPWStr)] 36 | StringBuilder InterfaceAlias, 37 | IntPtr Length 38 | ); 39 | 40 | private const int NDIS_IF_MAX_STRING_SIZE = 255; 41 | 42 | /// 43 | /// See https://en.wikipedia.org/wiki/List_of_Microsoft_Windows_versions 44 | /// 45 | private static readonly Version WindowsVistaVersion = new Version(6, 0); 46 | 47 | /// 48 | /// Fix for https://github.com/chmorgan/sharppcap/issues/57 49 | /// 50 | /// 51 | /// 52 | internal static string? GetInterfaceAlias(string pcapName) 53 | { 54 | if (Environment.OSVersion.Version < WindowsVistaVersion) 55 | { 56 | // Windows Vista or later required 57 | return null; 58 | } 59 | var guidIndex = pcapName.LastIndexOf('{'); 60 | if (guidIndex < 0 || !Guid.TryParse(pcapName.Substring(guidIndex), out var guid)) 61 | { 62 | return null; 63 | } 64 | uint retval; 65 | retval = ConvertInterfaceGuidToLuid(ref guid, out var luid); 66 | if (retval != 0) 67 | { 68 | return null; 69 | } 70 | 71 | var alias = new StringBuilder(NDIS_IF_MAX_STRING_SIZE + 1); 72 | retval = ConvertInterfaceLuidToAlias(ref luid, alias, (IntPtr)alias.Capacity); 73 | if (retval != 0) 74 | { 75 | return null; 76 | } 77 | return alias.ToString(); 78 | } 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /SharpPcap/MonitorMode.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2017 Noah Potash 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | namespace SharpPcap 6 | { 7 | /// 8 | /// The activation of monitor mode used when opening a device 9 | /// 10 | public enum MonitorMode : short 11 | { 12 | /// 13 | /// Monitor mode. 14 | /// Allows capturing of 802.11 wireless packets even when not associated 15 | /// with a network. 16 | /// 17 | Active = 1, 18 | 19 | /// 20 | /// Not monitor mode 21 | /// 22 | Inactive = 0 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /SharpPcap/PacketArrivalEventHandler.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2005 Tamir Gal 2 | // Copyright 2008-2010 Chris Morgan 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | namespace SharpPcap 7 | { 8 | /// A delegate for Packet Arrival events 9 | public delegate void PacketArrivalEventHandler(object sender, PacketCapture e); 10 | } 11 | -------------------------------------------------------------------------------- /SharpPcap/PacketCapture.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2005 Tamir Gal 2 | // Copyright 2008-2009 Chris Morgan 3 | // Copyright 2008-2009 Phillip Lemon 4 | // 5 | // SPDX-License-Identifier: MIT 6 | 7 | using System; 8 | 9 | namespace SharpPcap 10 | { 11 | /// 12 | /// Packet capture data 13 | /// 14 | public readonly ref struct PacketCapture 15 | { 16 | /// 17 | /// Packet that was captured 18 | /// 19 | public RawCapture GetPacket() { 20 | return new RawCapture(Device, Header, Data); 21 | } 22 | 23 | /// 24 | /// Device this EventArgs was generated for 25 | /// 26 | public ICaptureDevice Device { get; } 27 | 28 | public ICaptureHeader Header { get; } 29 | 30 | public ReadOnlySpan Data { get; } 31 | 32 | /// 33 | /// Constructor 34 | /// 35 | /// 36 | /// A 37 | /// 38 | /// 39 | /// A 40 | /// 41 | public PacketCapture(ICaptureDevice device, ICaptureHeader header, ReadOnlySpan data) 42 | { 43 | this.Header = header; 44 | this.Device = device; 45 | this.Data = data; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /SharpPcap/Pcap.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2005 Tamir Gal 2 | // Copyright 2008-2009 Chris Morgan 3 | // Copyright 2008-2009 Phillip Lemon 4 | // 5 | // SPDX-License-Identifier: MIT 6 | 7 | using System; 8 | using System.Runtime.InteropServices; 9 | using System.Text.RegularExpressions; 10 | 11 | namespace SharpPcap 12 | { 13 | /// 14 | /// Constants and static helper methods 15 | /// 16 | public class Pcap 17 | { 18 | /// Represents the infinite number for packet captures 19 | internal const int InfinitePacketCount = -1; 20 | 21 | /* interface is loopback */ 22 | internal const uint PCAP_IF_LOOPBACK = 0x00000001; 23 | internal const int MAX_PACKET_SIZE = 65536; 24 | 25 | // Constants for address families 26 | // These are set in a Pcap static initializer because the values 27 | // differ between Windows and Linux 28 | internal readonly static int AF_INET; 29 | internal readonly static int AF_PACKET; 30 | internal readonly static int AF_INET6; 31 | 32 | // Constants for pcap loop exit status. 33 | internal const int LOOP_USER_TERMINATED = -2; 34 | internal const int LOOP_EXIT_WITH_ERROR = -1; 35 | internal const int LOOP_COUNT_EXHAUSTED = 0; 36 | 37 | /// 38 | /// Returns the pcap version string retrieved via a call to pcap_lib_version() 39 | /// 40 | public static string Version 41 | { 42 | get 43 | { 44 | try 45 | { 46 | return LibPcap.LibPcapSafeNativeMethods.pcap_lib_version(); 47 | } 48 | catch 49 | { 50 | return "Pcap version can't be identified. It is likely that pcap is not installed " + 51 | "but you could be using a very old version."; 52 | } 53 | } 54 | } 55 | 56 | private static Version? _libpcapVersion; 57 | public static Version LibpcapVersion 58 | { 59 | get 60 | { 61 | _libpcapVersion = _libpcapVersion ?? GetLibpcapVersion(Version); 62 | return _libpcapVersion; 63 | } 64 | } 65 | 66 | public static Version SharpPcapVersion 67 | { 68 | get 69 | { 70 | return typeof(Pcap).Assembly.GetName().Version ?? new(); 71 | } 72 | } 73 | 74 | internal static Version GetLibpcapVersion(string version) 75 | { 76 | var regex = new Regex(@"libpcap version (\d+\.\d+(\.\d+)?)"); 77 | var match = regex.Match(version); 78 | if (match.Success) 79 | { 80 | return new Version(match.Groups[1].Value); 81 | } 82 | return new Version(); 83 | } 84 | 85 | static Pcap() 86 | { 87 | // happens to have the same value on Windows and Linux 88 | AF_INET = 2; 89 | 90 | // AF_PACKET = 17 on Linux, AF_NETBIOS = 17 on Windows 91 | // FIXME: need to resolve the discrepency at some point 92 | AF_PACKET = 17; 93 | 94 | if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 95 | { 96 | AF_INET6 = 10; // value for linux from socket.h 97 | } 98 | else 99 | { 100 | AF_INET6 = 23; // value for windows from winsock.h 101 | } 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /SharpPcap/PcapClock.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chris Morgan 2 | // Copyright 2021 Ayoub Kaanich 3 | // SPDX-License-Identifier: MIT 4 | 5 | using SharpPcap.LibPcap; 6 | using System; 7 | using System.Runtime.InteropServices; 8 | 9 | namespace SharpPcap 10 | { 11 | /// 12 | /// Provides interfaces to timestamp names, descriptions and features 13 | /// 14 | public class PcapClock 15 | { 16 | public string Name { get; } 17 | public string Description { get; } 18 | public TimestampSourceResolution Resolution { get; } // High, Low, Unknown 19 | 20 | public Synchronization Synchronized { get; } 21 | 22 | /// 23 | /// The type this clock maps back to 24 | /// 25 | public TimestampType TimestampType { get; } 26 | 27 | public PcapClock(TimestampType timestampType) 28 | { 29 | Name = TimestampName(timestampType); 30 | Description = TimestampDescription(timestampType); 31 | 32 | // Per https://www.tcpdump.org/manpages/pcap-tstamp.7.html, 33 | // "The precision of this time stamp is unspecified; it might or might not be synchronized with the host operating system's clock." 34 | if (timestampType == TimestampType.Host) 35 | { 36 | Resolution = TimestampSourceResolution.Unknown; 37 | Synchronized = Synchronization.Unknown; 38 | } else 39 | { 40 | Resolution = (timestampType == TimestampType.HostLowPrecision) ? TimestampSourceResolution.Low : TimestampSourceResolution.High; 41 | Synchronized = ((timestampType == TimestampType.AdapterUnsynced) || 42 | (timestampType == TimestampType.HostHighPrecisionUnsynced)) ? 43 | Synchronization.None : Synchronization.WithHostOS; 44 | } 45 | } 46 | 47 | private static string TimestampName(TimestampType number) 48 | { 49 | return LibPcapSafeNativeMethods.pcap_tstamp_type_val_to_name((int)number); 50 | } 51 | 52 | private static string TimestampDescription(TimestampType number) 53 | { 54 | return LibPcapSafeNativeMethods.pcap_tstamp_type_val_to_description((int)number); 55 | } 56 | 57 | /// 58 | /// See https://www.tcpdump.org/manpages/pcap-tstamp.7.html 59 | /// 60 | public enum Synchronization 61 | { 62 | Unknown, 63 | WithHostOS, 64 | None 65 | }; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /SharpPcap/PcapError.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | namespace SharpPcap 6 | { 7 | /// 8 | /// Error codes for the pcap API. 9 | /// See #define PCAP_ERROR* in https://github.com/the-tcpdump-group/libpcap/blob/master/pcap/pcap.h 10 | /// 11 | public enum PcapError : int 12 | { 13 | /// 14 | /// generic error code 15 | /// 16 | Generic = -1, 17 | /// 18 | /// loop terminated by pcap_breakloop 19 | /// 20 | Break = -2, 21 | /// 22 | /// the capture needs to be activated 23 | /// 24 | NotActivated = -3, 25 | /// 26 | /// the operation can't be performed on already activated captures 27 | /// 28 | Activated = -4, 29 | /// 30 | /// no such device exists 31 | /// 32 | NoSuchDevice = -5, 33 | /// 34 | /// this device doesn't support rfmon (monitor) mode 35 | /// 36 | RfmonNotSupported = -6, 37 | /// 38 | /// operation supported only in monitor mode 39 | /// 40 | NotRfmon = -7, 41 | /// 42 | /// no permission to open the device 43 | /// 44 | PermissionDenied = -8, 45 | /// 46 | /// interface isn't up 47 | /// 48 | InterfaceNotUp = -9, 49 | /// 50 | /// this device doesn't support setting the time stamp type 51 | /// 52 | TimestampTypeNotSupported = -10, 53 | /// 54 | /// you don't have permission to capture in promiscuous mode 55 | /// 56 | PromiscuousPermissionDenied = -11, 57 | /// 58 | /// the requested time stamp precision is not supported 59 | /// 60 | TimestampPrecisionNotSupported = -12, 61 | 62 | /// 63 | /// Defined by SharpPcap 64 | /// Corresponds to HRESULT of 65 | /// This means either the OS or the Libpcap version does not support requested configuration 66 | /// 67 | PlatformNotSupported = unchecked((int)0x80131539), 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /SharpPcap/PcapException.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2005 Tamir Gal 2 | // Copyright 2008-2009 Chris Morgan 3 | // Copyright 2008-2009 Phillip Lemon 4 | // 5 | // SPDX-License-Identifier: MIT 6 | 7 | using System; 8 | 9 | namespace SharpPcap 10 | { 11 | /// 12 | /// General Pcap Exception. 13 | /// 14 | public class PcapException : Exception 15 | { 16 | public PcapError Error { get; } 17 | 18 | internal PcapException() : base() 19 | { 20 | Error = PcapError.Generic; 21 | } 22 | 23 | internal PcapException(string msg) 24 | : base(msg) 25 | { 26 | Error = PcapError.Generic; 27 | } 28 | 29 | internal PcapException(string msg, PcapError error) 30 | : base(msg + $" (Error Code: {error})") 31 | { 32 | Error = error; 33 | } 34 | 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SharpPcap/Posix.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace SharpPcap 9 | { 10 | /// 11 | /// Posix code in here may seem complex but it serves an important 12 | /// purpose. 13 | /// 14 | /// Under Unix, pcap_loop(), pcap_dispatch(), pcap_next() and pcap_next_ex() 15 | /// all perform blocking read() calls at the os level that have NO timeout. 16 | /// If the user wishes to stop capturing on an adapter they will need to wait 17 | /// until the next packet arrives for the capture loop to wake up and look to see 18 | /// if it has been asked to shut down. This may be never in the case of inactive 19 | /// adapters or far longer than what the user desires. 20 | /// 21 | /// So, to avoid the issue we invoke the poll() system call. 22 | /// The thread sleeps on the poll() and only when woken 23 | /// up and indicating that data is available do we call one of the pcap 24 | /// data retrieval routines. This is how we avoid blocking for long periods 25 | /// or forever. 26 | /// 27 | /// Poll enables us to set a timeout. The timeout is chosen to be long 28 | /// enough to avoid a noticable performance impact from frequent looping 29 | /// but short enough to satisify the timing constraints of the Thread.Join() in 30 | /// the stop capture code. 31 | /// 32 | /// 33 | internal static class Posix 34 | { 35 | #pragma warning disable CS0649 36 | public struct Pollfd 37 | { 38 | public int fd; 39 | public PollEvents events; 40 | public PollEvents revents; 41 | } 42 | #pragma warning restore CS0649 43 | 44 | [Flags] 45 | public enum PollEvents : short 46 | { 47 | POLLIN = 0x0001, // There is data to read 48 | POLLPRI = 0x0002, // There is urgent data to read 49 | POLLOUT = 0x0004, // Writing now will not block 50 | POLLERR = 0x0008, // Error condition 51 | POLLHUP = 0x0010, // Hung up 52 | POLLNVAL = 0x0020, // Invalid request; fd not open 53 | } 54 | 55 | [DllImport("libc", SetLastError = true, EntryPoint = "poll")] 56 | internal static extern int Poll([In, Out] Pollfd[] ufds, uint nfds, int timeout); 57 | } 58 | 59 | 60 | } 61 | -------------------------------------------------------------------------------- /SharpPcap/RawCapture.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2011 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using PacketDotNet; 6 | 7 | namespace SharpPcap 8 | { 9 | /// 10 | /// Represents a raw captured packet 11 | /// 12 | public class RawCapture 13 | { 14 | /// 15 | /// Link layer from which this packet was captured 16 | /// 17 | public LinkLayers LinkLayerType 18 | { 19 | get; 20 | set; 21 | } 22 | 23 | /// 24 | /// The unix timeval when the packet was created 25 | /// 26 | public PosixTimeval Timeval 27 | { 28 | get; 29 | set; 30 | } 31 | 32 | /// Fetch data portion of the packet. 33 | /// 34 | /// Data as a class field vs. a virtual property improves performance 35 | /// significantly. ~2.5% when parsing the packet with Packet.Net and 36 | /// ~20% when reading each byte of the packet 37 | 38 | public byte[] Data; 39 | 40 | 41 | /// 42 | /// The length of the packet on the line 43 | /// 44 | public int PacketLength { get; set; } 45 | 46 | /// 47 | /// Creates a Packet object from the LinkLayerType and Data 48 | /// 49 | /// 50 | public virtual Packet GetPacket() 51 | { 52 | return Packet.ParsePacket(LinkLayerType, Data); 53 | } 54 | 55 | /// 56 | /// Constructor 57 | /// 58 | /// 59 | /// A 60 | /// 61 | /// 62 | /// A 63 | /// 64 | /// 65 | /// A 66 | /// 67 | public RawCapture(LinkLayers LinkLayerType, 68 | PosixTimeval Timeval, 69 | byte[] Data, 70 | int? packetLength = null) 71 | { 72 | this.LinkLayerType = LinkLayerType; 73 | this.Timeval = Timeval; 74 | this.Data = Data; 75 | this.PacketLength = packetLength ?? Data?.Length ?? 0; 76 | } 77 | 78 | #pragma warning disable CS8618 // Possible null reference return. 79 | public RawCapture(ICaptureDevice device, ICaptureHeader header, System.ReadOnlySpan data) 80 | { 81 | this.LinkLayerType = device.LinkType; 82 | this.Timeval = header.Timeval; 83 | this.Data = data.ToArray(); 84 | this.PacketLength = Data?.Length ?? 0; 85 | } 86 | #pragma warning restore CS8618 // Possible null reference return. 87 | 88 | /// Output this packet as a readable string 89 | public override System.String ToString() 90 | { 91 | var buffer = new System.Text.StringBuilder(); 92 | 93 | // build the output string 94 | buffer.AppendFormat("[RawCapture: LinkLayerType={0}, Timeval={1}]", 95 | LinkLayerType, 96 | Timeval); 97 | 98 | return buffer.ToString(); 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /SharpPcap/RemoteAuthentication.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2011-2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | using System.Net; 6 | using System.Runtime.InteropServices; 7 | using static SharpPcap.LibPcap.PcapUnmanagedStructures; 8 | 9 | namespace SharpPcap 10 | { 11 | /// 12 | /// Remote authentication type and parameters 13 | /// 14 | public class RemoteAuthentication 15 | { 16 | /// 17 | /// Type of authentication 18 | /// 19 | public AuthenticationTypes Type { get; set; } 20 | 21 | /// 22 | /// Username 23 | /// 24 | public string Username { get; set; } 25 | 26 | /// 27 | /// Password 28 | /// 29 | public string Password { get; set; } 30 | 31 | /// 32 | /// Constructor 33 | /// 34 | /// 35 | /// A 36 | /// 37 | /// 38 | /// A 39 | /// 40 | /// 41 | /// A 42 | /// 43 | public RemoteAuthentication(AuthenticationTypes Type, 44 | string Username, 45 | string Password) 46 | { 47 | this.Type = Type; 48 | this.Username = Username; 49 | this.Password = Password; 50 | } 51 | 52 | internal static pcap_rmtauth CreateAuth(RemoteAuthentication? credentials) 53 | { 54 | if (credentials == null) 55 | { 56 | return default; 57 | } 58 | 59 | var auth_type = (int)credentials.Type; 60 | 61 | return new pcap_rmtauth 62 | { 63 | type = new IntPtr(auth_type), 64 | username = credentials.Username, 65 | password = credentials.Password, 66 | }; 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /SharpPcap/SharpPcap.csproj: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | netstandard2.0;net8.0 11 | 6.3.1 12 | A packet capture framework for .NET 13 | Tamir Gal, Chris Morgan and others 14 | https://github.com/chmorgan/sharppcap 15 | false 16 | https://github.com/chmorgan/sharppcap 17 | true 18 | true 19 | true 20 | snupkg 21 | Tamir Gal, Chris Morgan and others 22 | 23 | SharpPcap is a cross-platform(Windows, Mac, Linux) packet capture framework for the .NET environment. 24 | It provides an API for capturing, injecting, analyzing and building packets using any .NET language such as C# and VB.NET. 25 | 26 | MIT 27 | true 28 | true 29 | enable 30 | Nullable 31 | 12.0 32 | 33 | 34 | true 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | all 43 | runtime; build; native; contentfiles; analyzers 44 | 45 | 46 | 47 | 48 | <_Parameter1>Test 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /SharpPcap/Statistics/CaptureMode.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | namespace SharpPcap.Statistics 6 | { 7 | /// 8 | /// The working mode of a Pcap device 9 | /// 10 | internal enum CaptureMode : int 11 | { 12 | /// 13 | /// Set a Pcap device to capture packets, Capture mode 14 | /// 15 | Packets = 0, 16 | 17 | /// 18 | /// Set a Pcap device to report statistics. 19 | ///
20 | /// Statistics mode is only supported in Npcap 21 | ///
22 | Statistics = 1 23 | }; 24 | } 25 | -------------------------------------------------------------------------------- /SharpPcap/Statistics/StatisticsEventArgs.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2005 Tamir Gal 2 | // Copyright 2009-2010 Chris Morgan 3 | // 4 | // SPDX-License-Identifier: MIT 5 | 6 | using SharpPcap.LibPcap; 7 | using System; 8 | 9 | namespace SharpPcap.Statistics 10 | { 11 | /// 12 | /// Event that contains statistics mode data 13 | /// NOTE: Npcap only 14 | /// 15 | public class StatisticsEventArgs : EventArgs 16 | { 17 | /// 18 | /// Constructor for a statistics mode event 19 | /// 20 | internal StatisticsEventArgs(StatisticsDevice device, PosixTimeval timeval, long packets, long bytes) 21 | { 22 | Device = device; 23 | Timeval = timeval; 24 | ReceivedPackets = packets; 25 | ReceivedBytes = bytes; 26 | } 27 | 28 | /// 29 | /// Device this EventArgs was generated for 30 | /// 31 | public StatisticsDevice Device { get; } 32 | 33 | /// 34 | /// This holds time value 35 | /// 36 | public PosixTimeval Timeval { get; } 37 | 38 | /// 39 | /// Number of packets received since last sample 40 | /// 41 | public long ReceivedPackets { get; } 42 | 43 | 44 | /// 45 | /// Number of bytes received since last sample 46 | /// 47 | public long ReceivedBytes { get; } 48 | 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /SharpPcap/StatisticsException.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2010 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | namespace SharpPcap 6 | { 7 | /// 8 | /// thrown when pcap_stats() reports an error 9 | /// 10 | public class StatisticsException : PcapException 11 | { 12 | /// 13 | /// string constructor 14 | /// 15 | /// 16 | /// A 17 | /// 18 | public StatisticsException(string msg) : base(msg) 19 | { 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SharpPcap/TimestampResolution.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | namespace SharpPcap 6 | { 7 | /// 8 | /// Precision / resolution of the timestamp 9 | /// 10 | /// See https://github.com/the-tcpdump-group/libpcap/blob/master/pcap/pcap.h#L511 11 | /// 12 | public enum TimestampResolution 13 | { 14 | Microsecond = 0, 15 | Nanosecond = 1 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /SharpPcap/TimestampSourceResolution.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | namespace SharpPcap 6 | { 7 | public enum TimestampSourceResolution 8 | { 9 | Low, 10 | High, 11 | Unknown 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /SharpPcap/TimestampType.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | namespace SharpPcap 6 | { 7 | /// 8 | /// Source of the timestamp 9 | /// See https://github.com/the-tcpdump-group/libpcap/blob/master/pcap/pcap.h#L498 for details 10 | /// 11 | public enum TimestampType : int 12 | { 13 | Host, 14 | HostLowPrecision, 15 | HostHighPrecision, 16 | Adapter, 17 | AdapterUnsynced, 18 | HostHighPrecisionUnsynced 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /SharpPcap/Tunneling/IPAddressConfiguration.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System.Net; 6 | 7 | namespace SharpPcap.Tunneling 8 | { 9 | /// 10 | /// IP Address configuration of the tunnel interface 11 | /// 12 | public class IPAddressConfiguration 13 | { 14 | // property names based on UnicastIPAddressInformation 15 | public IPAddress? Address { get; set; } 16 | public IPAddress? IPv4Mask { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SharpPcap/Tunneling/ITunnelDriver.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using Microsoft.Win32.SafeHandles; 6 | using System; 7 | using System.IO; 8 | using System.Net.NetworkInformation; 9 | 10 | namespace SharpPcap.Tunneling 11 | { 12 | internal interface ITunnelDriver 13 | { 14 | bool IsTunnelInterface(NetworkInterface networkInterface); 15 | FileStream Open(NetworkInterface networkInterface, IPAddressConfiguration address, DeviceConfiguration configuration); 16 | Version? GetVersion(NetworkInterface networkInterface, SafeFileHandle handle); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /SharpPcap/Tunneling/TunnelHeader.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | 6 | namespace SharpPcap.Tunneling 7 | { 8 | public class TunnelHeader : ICaptureHeader 9 | { 10 | public PosixTimeval Timeval { get; set; } 11 | 12 | public TunnelHeader() 13 | { 14 | Timeval = new PosixTimeval(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /SharpPcap/Tunneling/Unix/IffFlags.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | 7 | namespace SharpPcap.Tunneling.Unix 8 | { 9 | [Flags] 10 | internal enum IffFlags : short 11 | { 12 | Tun = 0x0001, 13 | Tap = 0x0002, 14 | NoPi = 0x1000, 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SharpPcap/Tunneling/Unix/Ifreq.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using SharpPcap.LibPcap; 6 | using System; 7 | using System.Net; 8 | using System.Net.Sockets; 9 | using System.Runtime.CompilerServices; 10 | using System.Runtime.InteropServices; 11 | using static SharpPcap.LibPcap.PcapUnmanagedStructures; 12 | 13 | namespace SharpPcap.Tunneling.Unix 14 | { 15 | [StructLayout(LayoutKind.Explicit)] 16 | internal struct IfReq 17 | { 18 | /// 19 | /// Interface name 20 | /// 21 | [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 16)] 22 | [FieldOffset(0)] 23 | internal string ifr_name; 24 | 25 | [FieldOffset(16)] 26 | internal short ifr_flags; 27 | 28 | [FieldOffset(16)] 29 | internal int ifr_ifindex; 30 | 31 | [FieldOffset(16)] 32 | internal int ifr_metric; 33 | 34 | [FieldOffset(16)] 35 | internal int ifr_mtu; 36 | 37 | [FieldOffset(16)] 38 | internal IntPtr ifr_data; 39 | 40 | [FieldOffset(16)] 41 | public sockaddr_in ifr_addr; 42 | 43 | // force total struct size to 40 44 | [FieldOffset(32)] 45 | private ulong _padding; 46 | 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /SharpPcap/Tunneling/Unix/IocDir.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | 7 | namespace SharpPcap.Tunneling.Unix 8 | { 9 | [Flags] 10 | internal enum IocDir : uint 11 | { 12 | None = 1U, 13 | Read = 2U, 14 | Write = 4U, 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SharpPcap/Tunneling/Unix/NetDeviceFlags.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | namespace SharpPcap.Tunneling.Unix 6 | { 7 | internal enum NetDeviceFlags : ushort 8 | { 9 | Up = 1 << 0, /* sysfs */ 10 | Broadcast = 1 << 1, /* volatile */ 11 | Debug = 1 << 2, /* sysfs */ 12 | Loopback = 1 << 3, /* volatile */ 13 | PoinToPoint = 1 << 4, /* volatile */ 14 | NoTrailers = 1 << 5, /* sysfs */ 15 | Running = 1 << 6, /* volatile */ 16 | NoArp = 1 << 7, /* sysfs */ 17 | Promisc = 1 << 8, /* sysfs */ 18 | AllMulti = 1 << 9, /* sysfs */ 19 | Master = 1 << 10, /* volatile */ 20 | Slave = 1 << 11, /* volatile */ 21 | Multicast = 1 << 12, /* sysfs */ 22 | Portsel = 1 << 13, /* sysfs */ 23 | AutoMedia = 1 << 14, /* sysfs */ 24 | Dynamic = 1 << 15, /* sysfs */ 25 | }; 26 | } 27 | -------------------------------------------------------------------------------- /SharpPcap/Tunneling/WinTap/TapIoControl.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | namespace SharpPcap.Tunneling.WinTap 6 | { 7 | /// 8 | /// See https://github.com/OpenVPN/tap-windows6/blob/master/src/tap-windows.h 9 | /// 10 | enum TapIoControl 11 | { 12 | /* Present in 8.1 */ 13 | 14 | GetMac = 1, 15 | GetVersion = 2, 16 | GetMtu = 3, 17 | GetInfo = 4, 18 | ConfigPointToPoint = 5, 19 | SetMediaStatus = 6, 20 | ConfigDhcpMasq = 7, 21 | GetLogLine = 8, 22 | ConfigDhcpSetOpt = 9, 23 | 24 | /* Added in 8.2 */ 25 | 26 | /** obsoletes ConfigPointToPoint */ 27 | ConfigTun = 10, 28 | 29 | /** Control whether 802.1Q headers are added for priority */ 30 | PriorityBehavior = 11, 31 | 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /SharpPcap/Tunneling/WinTap/WinFileAccess.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | 7 | namespace SharpPcap.Tunneling.WinTap 8 | { 9 | /// 10 | /// See https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew 11 | /// 12 | [Flags] 13 | enum WinFileAccess : uint 14 | { 15 | GenericRead = 0x80000000, 16 | GenericWrite = 0x40000000, 17 | GenericExecute = 0x20000000, 18 | GenericAll = 0x10000000, 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /SharpPcap/Tunneling/WinTap/WinFileAttributes.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | 7 | namespace SharpPcap.Tunneling.WinTap 8 | { 9 | /// 10 | /// See https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew 11 | /// 12 | [Flags] 13 | enum WinFileAttributes 14 | { 15 | Readonly = 0x00000001, 16 | Hidden = 0x00000002, 17 | System = 0x00000004, 18 | Directory = 0x00000010, 19 | Archive = 0x00000020, 20 | Device = 0x00000040, 21 | Normal = 0x00000080, 22 | Temporary = 0x00000100, 23 | SparseFile = 0x00000200, 24 | ReparsePoint = 0x00000400, 25 | Compressed = 0x00000800, 26 | Offline = 0x00001000, 27 | NotContentIndexed = 0x00002000, 28 | Encrypted = 0x00004000, 29 | 30 | Overlapped = 0x40000000, 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /SharpPcap/Tunneling/WinTap/WinFileCreation.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | 7 | namespace SharpPcap.Tunneling.WinTap 8 | { 9 | /// 10 | /// See https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew 11 | /// 12 | [Flags] 13 | enum WinFileCreation : uint 14 | { 15 | CreateNew = 1, 16 | CreateAlways = 2, 17 | OpenExisting = 3, 18 | OpenAlways = 4, 19 | TruncateExisting = 5, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SharpPcap/WinDivert/WinDivertAddress.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace SharpPcap.WinDivert 9 | { 10 | /// 11 | /// The WinDivertAddress structure represents the "address" of a captured or injected packet. The 12 | /// address includes the packet's timestamp, network interfaces, direction and other information. 13 | /// 14 | [StructLayout(LayoutKind.Sequential)] 15 | struct WinDivertAddress 16 | { 17 | public long Timestamp; 18 | public byte Layer; 19 | public byte Event; 20 | public WinDivertPacketFlags Flags; 21 | public uint IfIdx; 22 | public uint SubIfIdx; 23 | // Added bytes to match the struct size of WINDIVERT_ADDRESS, since we only map the first few fields 24 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = 56)] 25 | internal byte[] Padding; 26 | } 27 | } -------------------------------------------------------------------------------- /SharpPcap/WinDivert/WinDivertHeader.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | namespace SharpPcap.WinDivert 7 | { 8 | public class WinDivertHeader : ICaptureHeader 9 | { 10 | public uint InterfaceIndex { get; set; } 11 | public uint SubInterfaceIndex { get; set; } 12 | public WinDivertPacketFlags Flags { get; set; } 13 | 14 | public PosixTimeval Timeval { get; set; } 15 | 16 | public WinDivertHeader(PosixTimeval timeval) => Timeval = timeval; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SharpPcap/WinDivert/WinDivertLayer.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | namespace SharpPcap.WinDivert 6 | { 7 | /// 8 | /// Represents which part of the networking layer a WinDivert handle is operating on. 9 | /// 10 | public enum WinDivertLayer : uint 11 | { 12 | /// 13 | /// Represents the networking layer sans forwarded packets. 14 | /// 15 | Network = 0, 16 | 17 | /// 18 | /// Represents forwarded packets exclusively on the network layer. 19 | /// 20 | Forward = 1, 21 | 22 | Flow = 2, 23 | Socket = 3, 24 | Reflect = 4 25 | } 26 | } -------------------------------------------------------------------------------- /SharpPcap/WinDivert/WinDivertNative.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using System.Runtime.InteropServices; 7 | using System.Security; 8 | 9 | namespace SharpPcap.WinDivert 10 | { 11 | [SuppressUnmanagedCodeSecurity] 12 | internal static unsafe class WinDivertNative 13 | { 14 | const string WINDIVERT_DLL = "WinDivert.dll"; 15 | 16 | [DllImport(WINDIVERT_DLL, CallingConvention = CallingConvention.Cdecl, SetLastError = true)] 17 | internal static extern IntPtr WinDivertOpen([MarshalAs(UnmanagedType.LPStr)] string filter, WinDivertLayer layer, short priority, ulong flags); 18 | 19 | [DllImport(WINDIVERT_DLL, CallingConvention = CallingConvention.Cdecl, SetLastError = true)] 20 | internal static extern bool WinDivertRecvEx( 21 | IntPtr handle, 22 | ref byte pPacket, 23 | int packetLen, 24 | out int pRecvLen, 25 | ulong flags, 26 | [Out] WinDivertAddress[] pAddr, 27 | ref int pAddrLen, 28 | IntPtr lpOverlapped 29 | ); 30 | 31 | [DllImport(WINDIVERT_DLL, CallingConvention = CallingConvention.Cdecl)] 32 | internal static extern bool WinDivertHelperParsePacket( 33 | ref byte pPacket, 34 | int packetLen, 35 | IntPtr /* PWINDIVERT_IPHDR * */ ppIpHdr, 36 | IntPtr /* PWINDIVERT_IPV6HDR * */ ppIpv6Hdr, 37 | IntPtr /* UINT8 * */ pProtocol, 38 | IntPtr /* PWINDIVERT_ICMPHDR * */ ppIcmpHdr, 39 | IntPtr /* PWINDIVERT_ICMPV6HDR * */ ppIcmpv6Hdr, 40 | IntPtr /* PWINDIVERT_TCPHDR * */ ppTcpHdr, 41 | IntPtr /* PWINDIVERT_UDPHDR * */ ppUdpHdr, 42 | IntPtr /* PVOID * */ ppData, 43 | IntPtr /* UINT * */ pDataLen, 44 | IntPtr /* PVOID * */ ppNext, 45 | out int /* UINT * */ pNextLen 46 | ); 47 | 48 | [DllImport(WINDIVERT_DLL, CallingConvention = CallingConvention.Cdecl, SetLastError = true)] 49 | internal static extern bool WinDivertClose(IntPtr handle); 50 | 51 | [DllImport(WINDIVERT_DLL, CallingConvention = CallingConvention.Cdecl, SetLastError = true)] 52 | internal static extern bool WinDivertSetParam(IntPtr handle, WinDivertParam param, ulong value); 53 | 54 | [DllImport(WINDIVERT_DLL, CallingConvention = CallingConvention.Cdecl, SetLastError = true)] 55 | internal static extern bool WinDivertGetParam(IntPtr handle, WinDivertParam param, out ulong pValue); 56 | 57 | [DllImport(WINDIVERT_DLL, CallingConvention = CallingConvention.Cdecl, SetLastError = true)] 58 | internal static extern bool WinDivertHelperCompileFilter([MarshalAs(UnmanagedType.LPStr)] string filter, WinDivertLayer layer, IntPtr obj, uint objLen, out IntPtr errorStr, out uint errorPos); 59 | 60 | [DllImport(WINDIVERT_DLL, CallingConvention = CallingConvention.Cdecl, SetLastError = true)] 61 | internal static extern bool WinDivertSend(IntPtr handle, IntPtr pPacket, uint packetLen, out uint pSendLen, ref WinDivertAddress pAddr); 62 | } 63 | } -------------------------------------------------------------------------------- /SharpPcap/WinDivert/WinDivertPacketFlags.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | 7 | namespace SharpPcap.WinDivert 8 | { 9 | [Flags] 10 | public enum WinDivertPacketFlags : byte 11 | { 12 | Sniffed = 1 << 0, 13 | Outbound = 1 << 1, 14 | Loopback = 1 << 2, 15 | Impostor = 1 << 3, 16 | IPv6 = 1 << 4, 17 | IPChecksum = 1 << 5, 18 | TCPChecksum = 1 << 6, 19 | UDPChecksum = 1 << 7, 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SharpPcap/WinDivert/WinDivertParam.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | 7 | namespace SharpPcap.WinDivert 8 | { 9 | /// 10 | /// Generic configuration params for an opened WinDivert handle. 11 | /// 12 | [Flags] 13 | public enum WinDivertParam : uint 14 | { 15 | QueueLen = 0, 16 | QueueTime = 1, 17 | QueueSize = 2, 18 | } 19 | } -------------------------------------------------------------------------------- /SharpPcap/WinpkFilter/AdapterMode.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace SharpPcap.WinpkFilter 9 | { 10 | /// 11 | /// Used for setting adapter mode. 12 | /// 13 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 14 | internal struct AdapterMode 15 | { 16 | internal IntPtr AdapterHandle; 17 | internal AdapterModes Flags; 18 | } 19 | 20 | } -------------------------------------------------------------------------------- /SharpPcap/WinpkFilter/AdapterModes.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | 7 | namespace SharpPcap.WinpkFilter 8 | { 9 | /// 10 | /// Used to set the adapter flags. 11 | /// 12 | [Flags] 13 | public enum AdapterModes : uint 14 | { 15 | /// 16 | /// No flags. 17 | /// 18 | None = 0x00000000, 19 | 20 | /// 21 | /// Receive packets sent by MSTCP to network interface. 22 | /// The original packet is dropped. 23 | /// 24 | SentTunnel = 0x00000001, 25 | 26 | /// 27 | /// Receive packets sent from network interface to MSTCP. 28 | /// The original packet is dropped. 29 | /// 30 | RecvTunnel = 0x00000002, 31 | 32 | /// 33 | /// Receive packets sent from and to MSTCP and network interface. 34 | /// The original packet is dropped. 35 | /// 36 | Tunnel = SentTunnel | RecvTunnel, 37 | 38 | /// 39 | /// Receive packets sent by MSTCP to network interface. 40 | /// The original packet is still delivered to the network. 41 | /// 42 | SentListen = 0x00000004, 43 | 44 | /// 45 | /// Receive packets sent from network interface to MSTCP 46 | /// The original packet is still delivered to the network. 47 | /// 48 | RecvListen = 0x00000008, 49 | 50 | /// 51 | /// Receive packets sent from and to MSTCP and network interface. 52 | /// The original packet is dropped. 53 | /// 54 | Listen = SentListen | RecvListen, 55 | 56 | /// 57 | /// In promiscuous mode TCP/IP stack receives all. 58 | /// 59 | FilterDirect = 0x00000010, 60 | 61 | /// 62 | /// Passes loopback packet for processing. 63 | /// 64 | LoopbackFilter = 0x00000020, 65 | 66 | /// 67 | /// Silently drop loopback packets. 68 | /// 69 | LoopbackBlock = 0x00000040 70 | } 71 | 72 | } -------------------------------------------------------------------------------- /SharpPcap/WinpkFilter/DriverHandle.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using Microsoft.Win32.SafeHandles; 6 | 7 | namespace SharpPcap.WinpkFilter 8 | { 9 | public class DriverHandle : SafeHandleZeroOrMinusOneIsInvalid 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | public DriverHandle() 15 | : base(true) 16 | { 17 | } 18 | 19 | /// 20 | protected override bool ReleaseHandle() 21 | { 22 | NativeMethods.CloseFilterDriver(handle); 23 | 24 | return true; 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /SharpPcap/WinpkFilter/EthRequest.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace SharpPcap.WinpkFilter 9 | { 10 | /// 11 | /// Used for passing the read packet request to the driver. 12 | /// 13 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 14 | internal struct EthRequest 15 | { 16 | internal IntPtr AdapterHandle; 17 | internal IntPtr Buffer; 18 | } 19 | } -------------------------------------------------------------------------------- /SharpPcap/WinpkFilter/HardwarePacketFilters.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | 7 | namespace SharpPcap.WinpkFilter 8 | { 9 | 10 | /// 11 | /// The NDIS_PACKET_TYPE enum. 12 | /// See https://docs.microsoft.com/en-us/windows-hardware/drivers/network/oid-gen-current-packet-filter 13 | /// See https://www.ntkernel.com/docs/windows-packet-filter-documentation/ndisapi-c-2/sethwpacketfilter/ 14 | /// 15 | [Flags] 16 | public enum HardwarePacketFilters : uint 17 | { 18 | /// 19 | /// Used to reset the default filter 20 | /// 21 | None = 0x0000, 22 | /// 23 | /// Only packets directed to the workstation’s adapter are accepted 24 | /// 25 | Directed = 0x0001, 26 | /// 27 | /// Only the multicast packets belonging to the groups of which this adapter is a member are accepted. 28 | /// 29 | Multicast = 0x0002, 30 | /// 31 | /// Every multicast packet is accepted. 32 | /// 33 | AllMulticast = 0x0004, 34 | /// 35 | /// Only the broadcast packets are accepted. 36 | /// 37 | Broadcast = 0x0008, 38 | /// 39 | /// The promiscuous mode. Every incoming packet is accepted by the adapter. 40 | /// 41 | Promiscuous = 0x0020, 42 | /// 43 | /// All local packets, i.e. Directed + Broadcast + Multicast 44 | /// 45 | AllLocal = 0x0080, 46 | } 47 | 48 | } -------------------------------------------------------------------------------- /SharpPcap/WinpkFilter/IntermediateBuffer.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using System.Runtime.InteropServices; 7 | 8 | namespace SharpPcap.WinpkFilter 9 | { 10 | 11 | /// 12 | /// Contains packet both metadata and data 13 | /// 14 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 15 | internal unsafe struct IntermediateBuffer 16 | { 17 | internal IntermediateBufferHeader Header; 18 | internal fixed byte Frame[NativeMethods.MAX_ETHER_FRAME]; 19 | } 20 | 21 | /// 22 | /// Contains packet NDIS flags and WinPkFilter specific flags. 23 | /// 24 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 25 | internal struct IntermediateBufferHeader 26 | { 27 | #region LIST_ENTRY members 28 | internal IntPtr Flink; 29 | internal IntPtr Blink; 30 | #endregion 31 | 32 | internal PacketSource Source; 33 | internal uint Length; 34 | internal uint Flags; 35 | internal uint Dot1q; 36 | internal uint FilterId; 37 | 38 | internal uint Reserved0; 39 | internal uint Reserved1; 40 | internal uint Reserved2; 41 | internal uint Reserved3; 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /SharpPcap/WinpkFilter/Kernel32.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using System.Runtime.InteropServices; 7 | using System.Security; 8 | 9 | namespace SharpPcap.WinpkFilter 10 | { 11 | [SuppressUnmanagedCodeSecurity] 12 | internal static class Kernel32 13 | { 14 | [DllImport("kernel32.dll", EntryPoint = "RtlZeroMemory")] 15 | internal static extern void ZeroMemory(IntPtr destination, int length); 16 | } 17 | } -------------------------------------------------------------------------------- /SharpPcap/WinpkFilter/NativeMethods.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using System.Runtime.InteropServices; 7 | using System.Security; 8 | using Microsoft.Win32.SafeHandles; 9 | 10 | namespace SharpPcap.WinpkFilter 11 | { 12 | [SuppressUnmanagedCodeSecurity] 13 | static class NativeMethods 14 | { 15 | /// 16 | /// The file name of the Ndis Api DLL. 17 | /// 18 | private const string NDISAPI = "ndisapi.dll"; 19 | 20 | static NativeMethods() 21 | { 22 | IntermediateBufferHeaderSize = Marshal.SizeOf(); 23 | IntermediateBufferSize = Marshal.SizeOf(); 24 | } 25 | 26 | #region Methods 27 | 28 | [DllImport(NDISAPI)] 29 | internal static extern DriverHandle OpenFilterDriver(byte[] pszDriverName); 30 | 31 | [DllImport(NDISAPI)] 32 | internal static extern void CloseFilterDriver(IntPtr hOpen); 33 | 34 | [DllImport(NDISAPI)] 35 | internal static extern uint GetDriverVersion(DriverHandle hOpen); 36 | 37 | [DllImport(NDISAPI)] 38 | internal static extern bool GetTcpipBoundAdaptersInfo(DriverHandle hOpen, ref TcpAdapterList adapters); 39 | 40 | [DllImport(NDISAPI)] 41 | internal static extern bool SendPacketToMstcp(DriverHandle hOpen, ref EthRequest packet); 42 | 43 | [DllImport(NDISAPI)] 44 | internal static extern bool SendPacketToAdapter(DriverHandle hOpen, ref EthRequest packet); 45 | 46 | [DllImport(NDISAPI)] 47 | internal static extern bool ReadPacket(DriverHandle hOpen, ref EthRequest packet); 48 | 49 | [DllImport(NDISAPI)] 50 | internal static extern bool SetAdapterMode(DriverHandle hOpen, ref AdapterMode mode); 51 | 52 | [DllImport(NDISAPI)] 53 | internal static extern bool GetAdapterMode(DriverHandle hOpen, ref AdapterMode mode); 54 | 55 | [DllImport(NDISAPI)] 56 | internal static extern bool GetAdapterPacketQueueSize(DriverHandle hOpen, IntPtr hAdapter, ref uint dwSize); 57 | 58 | [DllImport(NDISAPI)] 59 | internal static extern bool SetPacketEvent(DriverHandle hOpen, IntPtr hAdapter, SafeWaitHandle hWin32Event); 60 | 61 | [DllImport(NDISAPI)] 62 | internal static extern bool SetHwPacketFilter(DriverHandle hOpen, IntPtr hAdapter, HardwarePacketFilters filter); 63 | 64 | [DllImport(NDISAPI)] 65 | internal static extern bool GetHwPacketFilter(DriverHandle hOpen, IntPtr hAdapter, ref HardwarePacketFilters pFilter); 66 | 67 | [DllImport(NDISAPI)] 68 | internal static extern bool ConvertWindows2000AdapterName( 69 | [MarshalAs(UnmanagedType.LPArray, SizeConst=ADAPTER_NAME_SIZE)] 70 | [In] 71 | byte[] szAdapterName, 72 | [MarshalAs(UnmanagedType.LPArray, SizeParamIndex=2)] 73 | [Out] 74 | byte[] szUserFriendlyName, 75 | uint dwUserFriendlyNameLength 76 | ); 77 | 78 | #endregion 79 | 80 | 81 | #region Sizes & Offsets 82 | 83 | /// 84 | /// The maximum adapter name length. 85 | /// 86 | internal const int ADAPTER_NAME_SIZE = 256; 87 | 88 | /// 89 | /// The adapter list size. 90 | /// 91 | internal const int ADAPTER_LIST_SIZE = 32; 92 | 93 | /// 94 | /// The maximum ether frame size. 95 | /// 96 | internal const int MAX_ETHER_FRAME = 1514; 97 | 98 | /// 99 | /// The ether address length. 100 | /// 101 | internal const int ETHER_ADDR_LENGTH = 6; 102 | 103 | internal static readonly int IntermediateBufferHeaderSize; 104 | internal static readonly int IntermediateBufferSize; 105 | 106 | #endregion 107 | } 108 | } -------------------------------------------------------------------------------- /SharpPcap/WinpkFilter/PacketSource.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | 6 | namespace SharpPcap.WinpkFilter 7 | { 8 | /// 9 | /// The packet flag. 10 | /// 11 | public enum PacketSource : uint 12 | { 13 | /// 14 | /// The packet was intercepted from MSTCP. 15 | /// 16 | System = 0x00000001, 17 | 18 | /// 19 | /// The packet was intercepted from the network interface. 20 | /// 21 | Interface = 0x00000002 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /SharpPcap/WinpkFilter/TcpAdapterList.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | 6 | using System; 7 | using System.Runtime.InteropServices; 8 | using static SharpPcap.WinpkFilter.NativeMethods; 9 | 10 | namespace SharpPcap.WinpkFilter 11 | { 12 | /// 13 | /// Used for requesting information about currently bound TCPIP adapters. 14 | /// 15 | [StructLayout(LayoutKind.Sequential, Pack = 1)] 16 | internal struct TcpAdapterList 17 | { 18 | internal uint AdapterCount; 19 | 20 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = ADAPTER_LIST_SIZE * ADAPTER_NAME_SIZE)] 21 | internal byte[] AdapterNames; 22 | 23 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = ADAPTER_LIST_SIZE)] 24 | internal IntPtr[] AdapterHandles; 25 | 26 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = ADAPTER_LIST_SIZE)] 27 | internal uint[] AdapterMediums; 28 | 29 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = ADAPTER_LIST_SIZE * ETHER_ADDR_LENGTH)] 30 | internal byte[] CurrentAddresses; 31 | 32 | [MarshalAs(UnmanagedType.ByValArray, SizeConst = ADAPTER_LIST_SIZE)] 33 | internal ushort[] MTUs; 34 | 35 | } 36 | 37 | } -------------------------------------------------------------------------------- /SharpPcap/WinpkFilter/WinpkFilterDriver.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using System.Collections.Generic; 7 | using System.Diagnostics; 8 | using System.IO; 9 | using System.Linq; 10 | using System.Text; 11 | 12 | namespace SharpPcap.WinpkFilter 13 | { 14 | public class WinpkFilterDriver : IDisposable 15 | { 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// The filter driver handle. 20 | /// The driver name bytes. 21 | protected WinpkFilterDriver(DriverHandle handle) 22 | { 23 | Handle = handle; 24 | } 25 | 26 | /// 27 | /// Gets the handle to the filter driver. 28 | /// 29 | public DriverHandle Handle { get; protected set; } 30 | 31 | /// 32 | public virtual void Dispose() 33 | { 34 | Handle?.Dispose(); 35 | } 36 | 37 | /// 38 | /// Opens the filter driver. 39 | /// 40 | /// The name of the driver. 41 | /// . 42 | /// Missing NDIS DLL 43 | public static WinpkFilterDriver Open(string driverName = "NDISRD") 44 | { 45 | var driverNameBytes = Encoding.GetEncoding("ISO-8859-1").GetBytes(driverName); 46 | var handle = NativeMethods.OpenFilterDriver(driverNameBytes); 47 | return new WinpkFilterDriver(handle); 48 | } 49 | 50 | /// 51 | /// Gets the native version of the filter driver. 52 | /// 53 | /// System.UInt32. 54 | public uint Version 55 | { 56 | get => NativeMethods.GetDriverVersion(Handle); 57 | } 58 | 59 | /// 60 | /// Gets the network adapters. 61 | /// 62 | /// The s. 63 | public IEnumerable GetNetworkDevices() 64 | { 65 | var adapterList = new TcpAdapterList(); 66 | NativeMethods.GetTcpipBoundAdaptersInfo(Handle, ref adapterList); 67 | 68 | for (var i = 0; i < adapterList.AdapterCount; i++) 69 | { 70 | var name = adapterList.AdapterNames.Skip(i * NativeMethods.ADAPTER_NAME_SIZE).Take(NativeMethods.ADAPTER_NAME_SIZE).ToArray(); 71 | var address = adapterList.CurrentAddresses.Skip(i * NativeMethods.ETHER_ADDR_LENGTH).Take(NativeMethods.ETHER_ADDR_LENGTH).ToArray(); 72 | yield return new WinpkFilterDevice( 73 | Handle, 74 | adapterList.AdapterHandles[i], 75 | name, 76 | adapterList.AdapterMediums[i], 77 | address, 78 | adapterList.MTUs[i] 79 | ); 80 | } 81 | } 82 | 83 | } 84 | } -------------------------------------------------------------------------------- /SharpPcap/WinpkFilter/WinpkFilterHeader.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | 6 | namespace SharpPcap.WinpkFilter 7 | { 8 | public class WinpkFilterHeader : ICaptureHeader 9 | { 10 | public PosixTimeval Timeval { get; set; } 11 | public PacketSource Source { get; set; } 12 | public uint Dot1q { get; set; } 13 | 14 | public WinpkFilterHeader() 15 | { 16 | Timeval = new PosixTimeval(); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /Test/ArpTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | using NUnit.Framework; 6 | using SharpPcap; 7 | using SharpPcap.LibPcap; 8 | 9 | namespace Test 10 | { 11 | [TestFixture] 12 | public class ArpTest 13 | { 14 | [Test] 15 | public void TestArp() 16 | { 17 | var d = TestHelper.GetPcapDevice(); 18 | var arp = new ARP(d); 19 | 20 | // timeout should not be null 21 | Assert.That(arp.Timeout.Ticks, Is.Not.Zero); 22 | 23 | // and we can set a timeout 24 | arp.Timeout = new TimeSpan(0, 0, 2); 25 | 26 | var destinationIP = new System.Net.IPAddress(new byte[] { 8, 8, 8, 8 }); 27 | 28 | // Note: We don't care about the success or failure here 29 | arp.Resolve(destinationIP); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Test/CaptureDeviceListTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | using SharpPcap; 6 | using NUnit.Framework; 7 | 8 | namespace Test 9 | { 10 | [TestFixture] 11 | public class CaptureDeviceListTest 12 | { 13 | /// 14 | /// Test that we can create a new device list 15 | /// 16 | [Test] 17 | public void CaptureDeviceListNew() 18 | { 19 | var deviceList = CaptureDeviceList.New(); 20 | Assert.That(deviceList, Is.Not.Null); 21 | Assert.That(deviceList, Is.Not.Empty); 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /Test/DeviceFixture.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using System.Collections; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using NUnit.Framework; 10 | using NUnit.Framework.Interfaces; 11 | using SharpPcap; 12 | using SharpPcap.LibPcap; 13 | 14 | namespace Test 15 | { 16 | 17 | public class DeviceFixture 18 | { 19 | private readonly LibPcapLiveDevice Device; 20 | public DeviceFixture(LibPcapLiveDevice device) 21 | { 22 | Device = device; 23 | } 24 | 25 | public LibPcapLiveDevice GetDevice() => Device; 26 | 27 | public override string ToString() 28 | { 29 | return Device.Name; 30 | } 31 | 32 | public static IEnumerable GetDevices() 33 | { 34 | var lists = new Dictionary> 35 | { 36 | { nameof(CaptureDeviceList), CaptureDeviceList.Instance }, 37 | { nameof(LibPcapLiveDeviceList), LibPcapLiveDeviceList.Instance } 38 | }; 39 | foreach (var list in lists) 40 | { 41 | Assert.That(list.Value, Is.Not.Empty, $"{list.Key} should not be empty"); 42 | } 43 | return lists.SelectMany(l => l.Value) 44 | // The bluetooth-monitor break the tests on circleci 45 | // With "Return code: -1" during Open 46 | .Where(d => d.Name != "bluetooth-monitor") 47 | // Semaphore CI have this interface, and it's always down 48 | .Where(d => d.Name != "virbr0-nic") 49 | // TAP interfaces, usually down until being used 50 | .Where(d => !d.Name.StartsWith("tap")) 51 | // From AppVeyor 52 | .Where(d => !d.Name.StartsWith("dbus")) 53 | .Distinct(); 54 | } 55 | } 56 | class CaptureDevicesAttribute : NUnitAttribute, IParameterDataSource 57 | { 58 | public IEnumerable GetData(IParameterInfo parameter) 59 | { 60 | return DeviceFixture.GetDevices() 61 | .Cast() 62 | .Select(d => new DeviceFixture(d)) 63 | .ToArray(); 64 | } 65 | } 66 | 67 | } 68 | 69 | -------------------------------------------------------------------------------- /Test/Exceptions.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | using SharpPcap; 6 | using NUnit.Framework; 7 | 8 | namespace Test 9 | { 10 | [TestFixture] 11 | public class Exceptions 12 | { 13 | [Test] 14 | public void ExceptionTest() 15 | { 16 | var deviceNotReadyException = new DeviceNotReadyException(); 17 | var statistics = new StatisticsException("test description"); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Test/LibPcapLiveDeviceTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | using NUnit.Framework; 6 | using SharpPcap; 7 | using SharpPcap.LibPcap; 8 | 9 | namespace Test 10 | { 11 | [TestFixture] 12 | public class LibPcapLiveDeviceTest 13 | { 14 | [Test] 15 | public void LibPcapLiveDeviceProperties() 16 | { 17 | var d = LibPcapLiveDeviceList.Instance[0]; 18 | Assert.That(d, Is.Not.Null); 19 | 20 | Assert.That(d.Addresses, Is.Not.Null); 21 | Console.WriteLine("Flags: {0}", d.Flags); 22 | Console.WriteLine("Loopback: {0}", d.Loopback); 23 | } 24 | 25 | /// 26 | /// Test specifying the timestamp type when opening devices 27 | /// 28 | /// 29 | [Category("Timestamp")] 30 | [Test] 31 | public void DeviceOpenWithTimestampType([CaptureDevices] DeviceFixture fixture) 32 | { 33 | using var device = (PcapDevice)fixture.GetDevice(); 34 | if (!(device is LibPcapLiveDevice)) 35 | return; 36 | 37 | var liveDevice = device as LibPcapLiveDevice; 38 | 39 | var timestampTypes = liveDevice.Interface.TimestampsSupported; 40 | 41 | Assert.That(timestampTypes, Is.Not.Empty); 42 | 43 | // open the device with each of its supported timestamp types 44 | foreach (var pcapClock in timestampTypes) 45 | { 46 | var configuration = new DeviceConfiguration(); 47 | configuration.TimestampType = pcapClock.TimestampType; 48 | liveDevice.Open(configuration); 49 | 50 | Assert.That(liveDevice.Interface.TimestampsSupported, Is.Not.Null); 51 | 52 | liveDevice.Close(); 53 | } 54 | } 55 | 56 | [Test] 57 | public void NonBlockingMode() 58 | { 59 | using var d = LibPcapLiveDeviceList.Instance[0]; 60 | Assert.That(d, Is.Not.Null); 61 | 62 | // assert that setting and getting non blocking mode 63 | // with a closed device 64 | Assert.Throws(() => d.NonBlockingMode = true); 65 | Assert.Throws(() => { var x = d.NonBlockingMode; }); 66 | 67 | // test that we can set the blocking mode on an open device 68 | d.Open(); 69 | d.NonBlockingMode = true; 70 | Assert.That(d.NonBlockingMode, Is.True); 71 | d.NonBlockingMode = false; 72 | Assert.That(d.NonBlockingMode, Is.False); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /Test/LibpcapVersionAttribute.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Ayoub Kaanich 2 | // SPDX-License-Identifier: MIT 3 | 4 | using NUnit.Framework; 5 | using NUnit.Framework.Interfaces; 6 | using NUnit.Framework.Internal; 7 | using System; 8 | using SemVersion.Parser; 9 | using SemVersion; 10 | using SharpPcap; 11 | 12 | namespace Test 13 | { 14 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method | AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)] 15 | public class LibpcapVersionAttribute : IncludeExcludeAttribute, IApplyToTest 16 | { 17 | 18 | /// 19 | /// Constructor taking one or more platforms 20 | /// 21 | /// Comma-delimited list of platforms 22 | public LibpcapVersionAttribute(string include) : base(include) { } 23 | 24 | /// 25 | /// Causes a test to be skipped if this LibpcapVersion is not satisfied. 26 | /// 27 | /// The test to modify 28 | public void ApplyToTest(NUnit.Framework.Internal.Test test) 29 | { 30 | if (test.RunState != RunState.NotRunnable && 31 | test.RunState != RunState.Ignored) 32 | { 33 | try 34 | { 35 | if ( 36 | (Include != null && !IsVersionSupported(Include)) || 37 | (Exclude != null && IsVersionSupported(Exclude)) 38 | ) 39 | { 40 | var reason = string.Format("Not supported on Libpcap v{0}", Pcap.LibpcapVersion); 41 | test.RunState = RunState.Skipped; 42 | test.Properties.Add(PropertyNames.SkipReason, reason); 43 | } 44 | } 45 | catch (Exception ex) 46 | { 47 | test.RunState = RunState.NotRunnable; 48 | test.Properties.Add(PropertyNames.SkipReason, ex.Message); 49 | } 50 | } 51 | } 52 | 53 | private static bool IsVersionSupported(string range) 54 | { 55 | var parser = new RangeParser(); 56 | var predicate = parser.Evaluate(range); 57 | var v = Pcap.LibpcapVersion; 58 | var version = new SemanticVersion(v.Major, v.Minor, Math.Max(v.Build, 0)); 59 | return predicate(version); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Test/LivePcapDeviceListTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | using NUnit.Framework; 6 | using SharpPcap.LibPcap; 7 | 8 | namespace Test 9 | { 10 | [TestFixture] 11 | public class LivePcapDeviceListTest 12 | { 13 | [Test] 14 | public void AllDevicesTest() 15 | { 16 | if(LibPcapLiveDeviceList.Instance.Count == 0) 17 | { 18 | throw new InvalidOperationException("No pcap supported devices found, are you running" + 19 | " as a user with access to adapters (root on Linux)?"); 20 | } else 21 | { 22 | Console.WriteLine("Found {0} devices", LibPcapLiveDeviceList.Instance.Count); 23 | } 24 | 25 | foreach(var d in LibPcapLiveDeviceList.Instance) 26 | { 27 | Console.WriteLine(d.ToString()); 28 | } 29 | } 30 | 31 | /// 32 | /// Test LibPcapDeviceList.New() and the index operator 33 | /// 34 | [Test] 35 | public void ListTest() 36 | { 37 | var dl = LibPcapLiveDeviceList.New(); 38 | 39 | // test that we can look up devices by name 40 | foreach (var d in dl) 41 | { 42 | Assert.That(dl[d.Name], Is.Not.Null); 43 | } 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Test/LivePcapDeviceSetFilterTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2009-2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | using System.Linq; 6 | using NUnit.Framework; 7 | using PacketDotNet; 8 | using SharpPcap; 9 | 10 | namespace Test 11 | { 12 | [TestFixture] 13 | [NonParallelizable] 14 | public class LivePcapDeviceSetFilterTest 15 | { 16 | [Test] 17 | public void SimpleFilter([CaptureDevices] DeviceFixture fixture) 18 | { 19 | // BPF is known to support those link layers, 20 | // support for other link layers such as NFLOG and USB is unknown 21 | var supportedLinks = new[] 22 | { 23 | LinkLayers.Ethernet, 24 | LinkLayers.Raw, 25 | LinkLayers.Null 26 | }; 27 | using var device = fixture.GetDevice(); 28 | device.Open(); 29 | if (!supportedLinks.Contains(device.LinkType)) 30 | { 31 | Assert.Inconclusive("NFLOG link-layer not supported"); 32 | } 33 | var filter = "tcp port 80"; 34 | device.Filter = filter; 35 | Assert.That(device.Filter, Is.EqualTo(filter)); 36 | } 37 | 38 | /// 39 | /// Test that we get the expected exception if PcapDevice.SetFilter() 40 | /// is called on a PcapDevice that has not been opened 41 | /// 42 | [Test] 43 | public void SetFilterExceptionIfDeviceIsClosed([CaptureDevices] DeviceFixture fixture) 44 | { 45 | var device = fixture.GetDevice(); 46 | Assert.Throws( 47 | () => device.Filter = "tcp port 80", 48 | "Did not catch the expected DeviceNotReadyException" 49 | ); 50 | } 51 | 52 | [SetUp] 53 | public void SetUp() 54 | { 55 | TestHelper.ConfirmIdleState(); 56 | } 57 | 58 | [TearDown] 59 | public void Cleanup() 60 | { 61 | TestHelper.ConfirmIdleState(); 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Test/MemorySafetyTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Ayoub Kaanich 2 | // SPDX-License-Identifier: MIT 3 | 4 | using NUnit.Framework; 5 | using PacketDotNet; 6 | using SharpPcap; 7 | using SharpPcap.LibPcap; 8 | using System; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | using static Test.TestHelper; 12 | 13 | namespace Test 14 | { 15 | /// 16 | /// Due to race conditions, it could happen that a device handle gets closed while being used by another thread 17 | /// We need to be able to at least prevent memory corruption 18 | /// If this test did what it should, you will see in the logs: 19 | /// "The active test run was aborted. Reason: Test host process crashed" 20 | /// We run each test 10 times in parallel, to make libpcap reuse freed memory and crash 21 | /// 22 | [TestFixture] 23 | [Category("MemorySafetry")] 24 | public class MemorySafetyTests 25 | { 26 | 27 | private readonly PcapInterface TestInterface = GetPcapDevice().Interface; 28 | 29 | [Test] 30 | [Parallelizable(ParallelScope.Children)] 31 | public void DisposeDuringCapture([Range(0, 9)] int _) 32 | { 33 | using var waitHandle = new AutoResetEvent(false); 34 | 35 | // We can't use the same device for async capturing and sending 36 | 37 | using var receiver = new LibPcapLiveDevice(TestInterface); 38 | using var sender = new LibPcapLiveDevice(TestInterface); 39 | 40 | // Configure sender 41 | sender.Open(); 42 | 43 | // Configure receiver 44 | receiver.Open(DeviceModes.Promiscuous); 45 | receiver.Filter = "ether proto 0xDEAD"; 46 | receiver.OnPacketArrival += (d, e) => 47 | { 48 | try 49 | { 50 | // Most simple form, dipose device while capture is running 51 | Task.Run(receiver.Dispose).Wait(); 52 | // Now try to access the memory of the packet 53 | Packet.ParsePacket(LinkLayers.Ethernet, e.Data.ToArray()); 54 | } 55 | finally 56 | { 57 | // Let test close 58 | waitHandle.Set(); 59 | } 60 | }; 61 | receiver.StartCapture(); 62 | 63 | // Send the packets 64 | var packet = EthernetPacket.RandomPacket(); 65 | packet.Type = (EthernetType)0xDEAD; 66 | sender.SendPacket(packet); 67 | 68 | // Wait for packets to arrive 69 | Assert.That(waitHandle.WaitOne(5000), Is.True); 70 | } 71 | 72 | 73 | [Test] 74 | [Parallelizable(ParallelScope.Children)] 75 | public void DisposeDuringTransmit([Range(0, 9)] int _) 76 | { 77 | using var device = new LibPcapLiveDevice(TestInterface); 78 | device.Open(); 79 | var queue = SendQueueTest.GetSendQueue(0xDEAD); 80 | Task.Run(() => 81 | { 82 | Thread.Sleep(TimeSpan.FromSeconds((double)SendQueueTest.DeltaTime)); 83 | device.Dispose(); 84 | }); 85 | try 86 | { 87 | queue.Transmit(device, SendQueueTransmitModes.Synchronized); 88 | } 89 | catch (Exception ex) 90 | when (ex is DeviceNotReadyException || ex is ObjectDisposedException) 91 | { 92 | // We are good, we disposed mid sending and we deserve the exception 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Test/PcapExceptionTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | using SharpPcap; 5 | using NUnit.Framework; 6 | 7 | namespace Test 8 | { 9 | [TestFixture] 10 | public class PcapExceptionTest 11 | { 12 | [Test] 13 | public void Exception() 14 | { 15 | var ex = new PcapException(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /Test/PcapStatisticsTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using NUnit.Framework; 7 | using SharpPcap; 8 | using SharpPcap.LibPcap; 9 | 10 | namespace Test 11 | { 12 | [TestFixture] 13 | [NonParallelizable] 14 | public class PcapStatisticsTest 15 | { 16 | /// 17 | /// Test retrieving statistics from the 'any' device, if one is found 18 | /// 19 | [Test] 20 | public void TestStatistics() 21 | { 22 | var devices = LibPcapLiveDeviceList.Instance; 23 | 24 | if (devices.Count == 0) 25 | { 26 | var error = "No pcap supported devices found, are you running" + 27 | " as a user with access to adapters (root on Linux)?"; 28 | throw new InvalidOperationException(error); 29 | } 30 | else 31 | { 32 | Console.WriteLine("Found {0} devices", devices.Count); 33 | } 34 | 35 | LibPcapLiveDevice dev = null; 36 | foreach (var d in devices) 37 | { 38 | Console.WriteLine(d.ToString()); 39 | 40 | if (d.Name == "any") 41 | { 42 | dev = d; 43 | } 44 | } 45 | 46 | // if we couldn't find the 'any' device (maybe we are running on Windows) 47 | // then just use the first device we can find, if there are any devices 48 | if ((dev == null) && devices.Count != 0) 49 | { 50 | dev = devices[0]; 51 | } 52 | 53 | Assert.That(dev, Is.Not.Null, "Unable to find a capture device"); 54 | 55 | // open a device for capture 56 | dev.Open(); 57 | 58 | // wait a little while so maybe packets will pass by 59 | System.Threading.Thread.Sleep(500); 60 | 61 | // retrieve the statistics 62 | var statistics = dev.Statistics; 63 | 64 | // output the statistics 65 | Console.WriteLine("statistics: {0}", statistics.ToString()); 66 | 67 | dev.Close(); 68 | } 69 | 70 | /// 71 | /// Ensure that we get an exception if we call PcapDevice.Statistics() 72 | /// on a closed device 73 | /// 74 | [Test] 75 | public void TestStatisticsException() 76 | { 77 | var devices = LibPcapLiveDeviceList.Instance; 78 | 79 | if (devices.Count == 0) 80 | { 81 | var error = "No pcap supported devices found, are you running" + 82 | " as a user with access to adapters (root on Linux)?"; 83 | throw new InvalidOperationException(error); 84 | } 85 | else 86 | { 87 | Console.WriteLine("Found {0} devices", devices.Count); 88 | } 89 | 90 | // ensure that we caught an exception 91 | Assert.Throws( 92 | () => devices[0].Statistics.ToString(), 93 | "Did not catch PcapDeviceNotReadyException" 94 | ); 95 | } 96 | 97 | [SetUp] 98 | public void SetUp() 99 | { 100 | TestHelper.ConfirmIdleState(); 101 | } 102 | 103 | [TearDown] 104 | public void Cleanup() 105 | { 106 | TestHelper.ConfirmIdleState(); 107 | } 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /Test/PcapTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Ayoub Kaanich 2 | // Copyright 2009 Chris Morgan 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using NUnit.Framework; 7 | using SharpPcap; 8 | 9 | namespace Test 10 | { 11 | [TestFixture] 12 | public class PcapTest 13 | { 14 | // Test that we can retrieve the Pcap version without any errors 15 | [Test] 16 | public void Version() 17 | { 18 | Console.WriteLine(Pcap.Version); 19 | } 20 | 21 | [Test] 22 | public void LibpcapVersionTest() 23 | { 24 | var libpcap = "libpcap version 1.10.0"; 25 | var versions = new[] { 26 | // https://github.com/nmap/nmap/issues/1566 27 | "libpcap version 1.9.0 (packet.dll version 0.992)", 28 | // Npcap 29 | "Npcap version 0.991, based on libpcap version 1.8.1", 30 | // Libpcap 31 | libpcap + " (with TPACKET_V3)", 32 | libpcap + " (SNF-only)", 33 | libpcap + " (Septel-only)", 34 | libpcap+ " (DPDK-only)", 35 | "DOS-" + libpcap, 36 | // WinPcap (legacy) 37 | "WinPcap version 4.1.3 (packet.dll version 4.1.0.2980), based on libpcap version 1.0 branch 1_0_rel0b (20091008)", 38 | // Currently installed 39 | Pcap.Version 40 | }; 41 | foreach (var ver in versions) 42 | { 43 | var version = Pcap.GetLibpcapVersion(ver); 44 | Assert.That(version, Is.GreaterThanOrEqualTo(new Version(1, 0))); 45 | } 46 | Assert.That(new Version(0, 0), Is.EqualTo(Pcap.GetLibpcapVersion("invalid"))); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Test/Performance/PacketReading.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2011-2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | using SharpPcap; 6 | using NUnit.Framework; 7 | using SharpPcap.LibPcap; 8 | 9 | namespace Test.Performance 10 | { 11 | [TestFixture] 12 | public class PacketReading 13 | { 14 | private readonly int packetsToRead = 10000000; 15 | 16 | [Category("Performance")] 17 | [Test] 18 | public void Benchmark() 19 | { 20 | int packetsRead = 0; 21 | var startTime = DateTime.Now; 22 | PacketCapture e; 23 | GetPacketStatus retval; 24 | while (packetsRead < packetsToRead) 25 | { 26 | using var captureDevice = new CaptureFileReaderDevice(TestHelper.GetFile("10k_packets.pcap")); 27 | captureDevice.Open(); 28 | 29 | do 30 | { 31 | retval = captureDevice.GetNextPacket(out e); 32 | if (retval == GetPacketStatus.PacketRead) packetsRead++; 33 | } 34 | while (retval == GetPacketStatus.PacketRead); 35 | 36 | } 37 | 38 | var endTime = DateTime.Now; 39 | 40 | var rate = new Rate(startTime, endTime, packetsRead, "packets captured"); 41 | 42 | Console.WriteLine("Benchmark {0}", rate.ToString()); 43 | } 44 | 45 | [Category("Performance")] 46 | [Test] 47 | public void BenchmarkGetNextPacketSpan() 48 | { 49 | int packetsRead = 0; 50 | var startTime = DateTime.Now; 51 | GetPacketStatus res; 52 | 53 | PacketCapture e; 54 | while (packetsRead < packetsToRead) 55 | { 56 | using var captureDevice = new CaptureFileReaderDevice(TestHelper.GetFile("10k_packets.pcap")); 57 | captureDevice.Open(); 58 | 59 | do 60 | { 61 | res = captureDevice.GetNextPacket(out e); 62 | if (res == GetPacketStatus.PacketRead) packetsRead++; 63 | } 64 | while (res == GetPacketStatus.PacketRead); 65 | } 66 | 67 | var endTime = DateTime.Now; 68 | 69 | var rate = new Rate(startTime, endTime, packetsRead, "packets captured"); 70 | 71 | Console.WriteLine("BenchmarkGetNextPacketSpan {0}", rate.ToString()); 72 | } 73 | 74 | [Category("Performance")] 75 | [Test] 76 | public unsafe void BenchmarkICaptureDeviceUnsafe() 77 | { 78 | int packetsRead = 0; 79 | var startTime = DateTime.Now; 80 | PacketCapture e; 81 | GetPacketStatus retval; 82 | while (packetsRead < packetsToRead) 83 | { 84 | using var captureDevice = new CaptureFileReaderDevice(TestHelper.GetFile("10k_packets.pcap")); 85 | captureDevice.Open(); 86 | 87 | do 88 | { 89 | retval = captureDevice.GetNextPacket(out e); 90 | if (retval == GetPacketStatus.PacketRead) packetsRead++; 91 | } 92 | while (retval == GetPacketStatus.PacketRead); 93 | } 94 | 95 | var endTime = DateTime.Now; 96 | 97 | var rate = new Rate(startTime, endTime, packetsRead, "packets captured"); 98 | 99 | Console.WriteLine("BenchmarkICaptureDeviceUnsafe {0}", rate.ToString()); 100 | } 101 | } 102 | } 103 | 104 | -------------------------------------------------------------------------------- /Test/Performance/Rate.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2011-2021 Chris Morgan 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System; 5 | 6 | namespace Test.Performance 7 | { 8 | /// 9 | /// Compute a rate given a start and end DateTime and an event count 10 | /// 11 | public class Rate 12 | { 13 | private TimeSpan Elapsed; 14 | private readonly string EventType; 15 | private readonly int EventCount; 16 | 17 | public Rate(DateTime Start, DateTime End, 18 | int EventCount, string EventType) 19 | { 20 | Elapsed = End - Start; 21 | this.EventCount = EventCount; 22 | this.EventType = EventType; 23 | } 24 | 25 | /// 26 | /// Returns the rate in terms of events per second 27 | /// 28 | public double RatePerSecond 29 | { 30 | get 31 | { 32 | return ((Double)EventCount / (Double)Elapsed.Ticks) * TimeSpan.TicksPerSecond; 33 | } 34 | } 35 | 36 | public override string ToString() 37 | { 38 | return String.Format(" {0,10} {1} at a rate of {2,12} / second ({3} seconds elapsed)", 39 | EventCount, 40 | EventType, 41 | RatePerSecond.ToString("n"), 42 | Elapsed); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Test/PosixTimevalTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2010 Chris Morgan 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using NUnit.Framework; 7 | using SharpPcap; 8 | 9 | namespace Test.Misc 10 | { 11 | [TestFixture] 12 | public class PosixTimevalTest 13 | { 14 | static PosixTimeval p1 = new PosixTimeval(100, 50); 15 | static PosixTimeval p2 = new PosixTimeval(100, 100); 16 | static PosixTimeval p3 = new PosixTimeval(200, 20); 17 | 18 | static PosixTimeval p4 = new PosixTimeval(100, 50); 19 | 20 | static PosixTimeval p5 = new PosixTimeval(100, 20); 21 | 22 | // Test posix timeval comparison operators 23 | [Test] 24 | public void OperatorTest() 25 | { 26 | Assert.Multiple(() => 27 | { 28 | Assert.That(p1 < p2, Is.True, "p1 < p2"); 29 | Assert.That(p2 < p1, Is.False, "p2 < p1"); 30 | Assert.That(p2 < p3, Is.True, "p2 < p3"); 31 | Assert.That(p1 < p3, Is.True, "p1 < p3"); 32 | Assert.That(p1 < p5, Is.False, "p1 < p5"); 33 | 34 | Assert.That(p2 > p1, Is.True, "p2 > p1"); 35 | Assert.That(p3 > p2, Is.True, "p3 > p2"); 36 | Assert.That(p3 > p1, Is.True, "p3 > p1"); 37 | 38 | Assert.That(p1 != p2, Is.True, "p1 != p2"); 39 | 40 | Assert.That(p1 == p4, Is.True, "p1 == p4"); 41 | 42 | Assert.That(p1 <= p2, Is.True, "p1 <= p2"); 43 | Assert.That(p1 <= p3, Is.True, "p1 <= p3"); 44 | Assert.That(p2 <= p1, Is.False, "p2 <= p1"); 45 | Assert.That(p2 >= p1, Is.True, "p2 >= p1"); 46 | 47 | Assert.That(p1.CompareTo(p4), Is.EqualTo(0)); 48 | Assert.That(p1.CompareTo(p2), Is.EqualTo(-1)); 49 | Assert.That(p2.CompareTo(p1), Is.EqualTo(1)); 50 | 51 | Assert.That(p1.Equals(p4), Is.EqualTo(true)); 52 | Assert.That(p1.Equals(p2), Is.EqualTo(false)); 53 | }); 54 | } 55 | 56 | // Test string formatting output 57 | [Test] 58 | public void ToStringTest() 59 | { 60 | var p1 = new PosixTimeval(123, 12345); 61 | 62 | Assert.That(p1.ToString(), Is.EqualTo("123.012345s")); 63 | } 64 | 65 | [Test] 66 | public void HashTest() 67 | { 68 | Assert.That(p2.GetHashCode(), Is.Not.EqualTo(p1.GetHashCode())); 69 | Assert.That(p4.GetHashCode(), Is.EqualTo(p1.GetHashCode())); 70 | } 71 | 72 | [Test] 73 | public void DateTimeConversion() 74 | { 75 | var now = DateTime.Now; 76 | var pX = new PosixTimeval(now); 77 | Assert.That(now.ToUniversalTime(), Is.EqualTo(pX.Date).Within(TimeSpan.FromMilliseconds(1))); 78 | } 79 | 80 | [Test] 81 | public void EmptyConstructor() 82 | { 83 | var pX = new PosixTimeval(); 84 | Assert.That(DateTime.UtcNow, Is.EqualTo(pX.Date).Within(TimeSpan.FromMilliseconds(1))); 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Test/SendPacketTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Ayoub Kaanich 2 | // Copyright 2020-2021 Chris Morgan 3 | // SPDX-License-Identifier: MIT 4 | 5 | using NUnit.Framework; 6 | using PacketDotNet; 7 | using SharpPcap; 8 | using SharpPcap.LibPcap; 9 | using System; 10 | using System.Collections.Generic; 11 | using System.Linq; 12 | using static Test.TestHelper; 13 | using static System.TimeSpan; 14 | 15 | namespace Test 16 | { 17 | [TestFixture] 18 | [NonParallelizable] 19 | [Category("SendPacket")] 20 | public class SendPacketTest 21 | { 22 | private const string Filter = "ether proto 0x1234"; 23 | 24 | [Test] 25 | public void TestSendPacketTest() 26 | { 27 | var packet = EthernetPacket.RandomPacket(); 28 | packet.Type = (EthernetType)0x1234; 29 | var received = RunCapture(Filter, (device) => 30 | { 31 | // test all forms of SendPacket() 32 | device.SendPacket(packet); 33 | var rawCapture = new RawCapture(LinkLayers.Ethernet, new PosixTimeval(), packet.Bytes); 34 | device.SendPacket(rawCapture); 35 | device.SendPacket(packet, packet.TotalPacketLength); 36 | device.SendPacket(packet.Bytes, packet.Bytes.Length); 37 | }); 38 | Assert.That(received, Has.Count.EqualTo(4)); 39 | Assert.That(received[0].Data, Is.EquivalentTo(packet.Bytes)); 40 | } 41 | 42 | [SetUp] 43 | public void SetUp() 44 | { 45 | TestHelper.ConfirmIdleState(); 46 | } 47 | 48 | [TearDown] 49 | public void Cleanup() 50 | { 51 | TestHelper.ConfirmIdleState(); 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Test/Test.csproj: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | true 11 | net8.0 12 | $(TargetFrameworks);net48 13 | false 14 | opencover 15 | 16 | 17 | 18 | all 19 | runtime; build; native; contentfiles; analyzers 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | PreserveNewest 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Test/TestUser.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2020-2021 Ayoub Kaanich 2 | // SPDX-License-Identifier: MIT 3 | using NUnit.Framework; 4 | using System; 5 | using System.Diagnostics; 6 | using System.DirectoryServices.AccountManagement; 7 | using System.Runtime.InteropServices; 8 | 9 | namespace Test 10 | { 11 | public static class TestUser 12 | { 13 | public const string Username = "sharppcaptestuser"; 14 | public const string Password = "password"; 15 | 16 | public static bool Create() 17 | { 18 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 19 | { 20 | try 21 | { 22 | Delete(); 23 | var ctx = new PrincipalContext(ContextType.Machine); 24 | using (var user = new UserPrincipal(ctx, Username, Password, true)) 25 | { 26 | user.Save(); 27 | } 28 | return true; 29 | } 30 | catch (PrincipalException) 31 | { 32 | return false; 33 | } 34 | } 35 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 36 | { 37 | Bash("useradd", Username, "--groups", "sudo"); 38 | Bash("bash", "-c", $"\"echo -e {Username}:{Password} | chpasswd\""); 39 | } 40 | // OS not supported 41 | return false; 42 | } 43 | 44 | private static void Bash(string cmd, params string[] args) 45 | { 46 | var arguments = string.Join(" ", args); 47 | var info = new ProcessStartInfo 48 | { 49 | FileName = cmd, 50 | Arguments = arguments, 51 | UseShellExecute = false, 52 | RedirectStandardOutput = true, 53 | RedirectStandardError = true 54 | }; 55 | var process = Process.Start(info); 56 | 57 | process.OutputDataReceived += (s, e) => Console.Out.WriteLine(e.Data); 58 | process.ErrorDataReceived += (s, e) => Console.Error.WriteLine(e.Data); 59 | 60 | process.BeginOutputReadLine(); 61 | process.BeginErrorReadLine(); 62 | if (!process.WaitForExit(10000)) 63 | { 64 | throw new TimeoutException($"Command '{cmd} {arguments}' timed out"); 65 | } 66 | Assert.That(process.ExitCode, Is.Zero); 67 | } 68 | 69 | public static void Delete() 70 | { 71 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) 72 | { 73 | var ctx = new PrincipalContext(ContextType.Machine); 74 | var user = UserPrincipal.FindByIdentity(ctx, Username); 75 | user?.Delete(); 76 | } 77 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) 78 | { 79 | Bash("userdel", Username); 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Test/ThreadSafeTests.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2022 Ayoub Kaanich 2 | // SPDX-License-Identifier: MIT 3 | 4 | using NUnit.Framework; 5 | using SharpPcap; 6 | using SharpPcap.LibPcap; 7 | using System; 8 | using System.Linq; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | namespace Test 13 | { 14 | /// 15 | /// This is not about making PcapDevice 100% thread safe 16 | /// this is about prevent memory access violation 17 | /// 18 | [TestFixture] 19 | public class ThreadSafeTests 20 | { 21 | 22 | [Test] 23 | // Thread Safety is crashing in .NET 8 so skip it for now. 24 | #if NET 25 | [Explicit] 26 | #endif 27 | public void TestThreadSafety() 28 | { 29 | var pcapDevice = TestHelper.GetPcapDevice(); 30 | var devices = Enumerable.Range(0, Environment.ProcessorCount) 31 | .Select(_ => new LibPcapLiveDevice(pcapDevice.Interface)) 32 | .ToArray(); 33 | 34 | foreach (var device in devices) 35 | { 36 | Initialize(device); 37 | } 38 | Thread.Sleep(TimeSpan.FromMinutes(1)); 39 | foreach (var device in devices) 40 | { 41 | device.Dispose(); 42 | } 43 | } 44 | 45 | private static void Initialize(LibPcapLiveDevice device) 46 | { 47 | var retry = 0; 48 | while (retry <= 7) 49 | { 50 | try 51 | { 52 | device.Open(DeviceModes.Promiscuous); 53 | device.OnPacketArrival += Device_OnPacketArrival; 54 | device.StartCapture(); 55 | return; 56 | } 57 | catch (PcapException) 58 | { 59 | // Race condition while closing/opening device, retry 60 | retry++; 61 | } 62 | } 63 | } 64 | 65 | private static void Device_OnPacketArrival(object sender, PacketCapture e) 66 | { 67 | try 68 | { 69 | var device = (LibPcapLiveDevice)sender; 70 | Task.Run(() => 71 | { 72 | try 73 | { 74 | device.Dispose(); 75 | Thread.Sleep(1); 76 | Initialize(device); 77 | } 78 | catch (Exception ex) 79 | { 80 | Console.WriteLine($"Exception happened in thread:{ex}"); 81 | } 82 | }); 83 | // Trigger the data to be read from the pcap_t memory 84 | e.GetPacket(); 85 | } 86 | catch (DeviceNotReadyException) 87 | { 88 | // Pass, normal 89 | } 90 | catch (ObjectDisposedException) 91 | { 92 | // Pass, normal 93 | } 94 | } 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Test/Tunneling/IpHelper.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System; 6 | using System.Linq; 7 | using System.Net; 8 | using System.Net.NetworkInformation; 9 | using System.Net.Sockets; 10 | using System.Runtime.InteropServices; 11 | using System.Threading; 12 | 13 | namespace Test.Tunneling 14 | { 15 | class IpHelper 16 | { 17 | 18 | /// 19 | /// Wait for interface to have an effective IP, and return it 20 | /// 21 | /// 22 | /// 23 | /// 24 | internal static IPAddress GetIPAddress(NetworkInterface nic, int retry = 10) 25 | { 26 | IPAddress pendingIp = null; 27 | // Update interface reference, since addresses could change after interface opened 28 | nic = NetworkInterface.GetAllNetworkInterfaces() 29 | .First(n => n.Id.Equals(nic.Id)); 30 | foreach (var addr in nic.GetIPProperties().UnicastAddresses) 31 | { 32 | if (addr.Address.AddressFamily == AddressFamily.InterNetwork) 33 | { 34 | if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && 35 | addr.DuplicateAddressDetectionState != DuplicateAddressDetectionState.Preferred) 36 | { 37 | // We have an IP, but it's not ready for use yet 38 | pendingIp = addr.Address; 39 | } 40 | else 41 | { 42 | return addr.Address; 43 | } 44 | } 45 | } 46 | if (retry > 0) 47 | { 48 | while (nic.OperationalStatus != OperationalStatus.Up) 49 | { 50 | Console.WriteLine($"interface '{nic.Name}' is {nic.OperationalStatus}"); 51 | } 52 | if (pendingIp != null) 53 | { 54 | Console.WriteLine($"interface '{nic.Name}' have pending IP {pendingIp}"); 55 | Thread.Sleep(1000); 56 | } 57 | return GetIPAddress(nic, retry - 1); 58 | } 59 | throw new NotSupportedException($"Failed to get interface '{nic.Name}' address."); 60 | } 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /Test/Tunneling/UdpTester.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2021 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using NUnit.Framework; 6 | using PacketDotNet; 7 | using System; 8 | using System.Net; 9 | using System.Net.NetworkInformation; 10 | using System.Net.Sockets; 11 | using System.Threading.Tasks; 12 | 13 | namespace Test.Tunneling 14 | { 15 | class UdpTester : IDisposable 16 | { 17 | private readonly IPAddress LocalIp; 18 | private readonly UdpClient Client; 19 | 20 | internal static readonly ushort Port = 4422; 21 | private static readonly PhysicalAddress BroadcastMac = PhysicalAddress.Parse("FFFFFFFFFFFF"); 22 | 23 | public byte[] LastReceivedData { get; private set; } 24 | 25 | public UdpTester(IPAddress localIp) 26 | { 27 | LocalIp = localIp; 28 | Client = new UdpClient(new IPEndPoint(localIp, Port)); 29 | Client.EnableBroadcast = true; 30 | Task.Run(ReceiveLoop); 31 | } 32 | 33 | public void Dispose() 34 | { 35 | Client.Dispose(); 36 | } 37 | 38 | public void Broadcast(byte[] data) 39 | { 40 | var remote = new IPEndPoint(IPAddress.Broadcast, Port); 41 | Client.Send(data, data.Length, remote); 42 | } 43 | 44 | /// 45 | /// Check that given packet matches what we would send back 46 | /// 47 | /// 48 | /// 49 | /// 50 | public void AssertMatches(Packet packet, byte[] data) 51 | { 52 | Assert.That(packet, Is.Not.Null); 53 | var ip = packet.Extract(); 54 | var udp = packet.Extract(); 55 | 56 | Assert.That(ip, Is.Not.Null); 57 | Assert.That(udp, Is.Not.Null); 58 | 59 | Assert.That(Port, Is.EqualTo(udp.SourcePort)); 60 | Assert.That(Port, Is.EqualTo(udp.DestinationPort)); 61 | Assert.That(ip.SourceAddress, Is.EqualTo(LocalIp)); 62 | 63 | Assert.That(udp.PayloadData, Is.EqualTo(data).AsCollection); 64 | } 65 | 66 | /// 67 | /// Create packet that would be replied to by this listener if correctly injected 68 | /// 69 | /// 70 | /// 71 | public Packet GetReceivablePacket(byte[] data) 72 | { 73 | var ipBytes = LocalIp.GetAddressBytes(); 74 | ipBytes[3]++; 75 | var fakeIp = new IPAddress(ipBytes); 76 | var fakeMac = PhysicalAddress.Parse("001122334455"); 77 | var eth = new EthernetPacket(fakeMac, BroadcastMac, EthernetType.IPv6); 78 | var ip = new IPv4Packet(fakeIp, LocalIp); 79 | var udp = new UdpPacket(Port, Port); 80 | 81 | eth.PayloadPacket = ip; 82 | ip.PayloadPacket = udp; 83 | udp.PayloadData = data; 84 | 85 | udp.UpdateCalculatedValues(); 86 | ip.UpdateCalculatedValues(); 87 | 88 | udp.UpdateUdpChecksum(); 89 | ip.UpdateIPChecksum(); 90 | 91 | return eth; 92 | } 93 | 94 | private void ReceiveLoop() 95 | { 96 | try 97 | { 98 | while (true) 99 | { 100 | var remote = new IPEndPoint(IPAddress.Any, 0); 101 | var receiveBytes = Client.Receive(ref remote); 102 | if (!LocalIp.Equals(remote.Address)) 103 | { 104 | LastReceivedData = receiveBytes; 105 | } 106 | } 107 | } 108 | catch 109 | { 110 | // end of connection 111 | } 112 | } 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /Test/WebHelper.cs: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Ayoub Kaanich 2 | // SPDX-License-Identifier: MIT 3 | 4 | using System.Net; 5 | 6 | namespace Test 7 | { 8 | 9 | /// 10 | /// cloudflair has a website at this address, should be accessible from any 11 | /// computer with a connection to the Internet 12 | /// 13 | internal static class WebHelper 14 | { 15 | public static readonly IPAddress Address = IPAddress.Parse("1.1.1.1"); 16 | 17 | public static WebExceptionStatus WebFetch() 18 | { 19 | try 20 | { 21 | var req = WebRequest.Create("http://" + Address.ToString()); 22 | req.Timeout = 3000; 23 | req.GetResponse(); 24 | return WebExceptionStatus.Success; 25 | } 26 | catch (WebException we) 27 | { 28 | return we.Status; 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Test/WinDivert/IpHelperTest.cs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2020 Ayoub Kaanich 2 | // 3 | // SPDX-License-Identifier: MIT 4 | 5 | using System.Net; 6 | using NUnit.Framework; 7 | using SharpPcap.WinDivert; 8 | 9 | namespace Test.WinDivert 10 | { 11 | [TestFixture] 12 | [Category("WinDivert")] 13 | [Platform("Win", Reason = "IpHelper.dll is only available for Windows")] 14 | public class IpHelperTest 15 | { 16 | [Test] 17 | public void Test() 18 | { 19 | var localhost = IPAddress.Parse("127.0.0.1"); 20 | var bestInterface = IpHelper.GetBestInterface(localhost); 21 | Assert.That(bestInterface, Is.Not.Null); 22 | 23 | var external = IPAddress.Parse("8.8.8.8"); 24 | var bestInterfaceIndex = IpHelper.GetBestInterfaceIndex(external); 25 | Assert.That(IpHelper.IsOutbound(bestInterfaceIndex, external, localhost), Is.False); 26 | Assert.That(IpHelper.IsOutbound(bestInterfaceIndex, localhost, external), Is.False); 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /Test/capture_files/10k_packets.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotpcap/sharppcap/bfedf297e7410ffcf44e05d14f7fbef304f20895/Test/capture_files/10k_packets.pcap -------------------------------------------------------------------------------- /Test/capture_files/README: -------------------------------------------------------------------------------- 1 | arp_request_response.pcap 2 | - arp request 3 | - arp response 4 | 5 | udp_dns_request_response.pcap 6 | - dns request 7 | - dns response 8 | 9 | test_stream.pcap 10 | - Two tcp packets 11 | - One udp packet 12 | - One udp dns packet 13 | - One arp packet 14 | - One icmp packet 15 | 16 | ipv6_icmpv6_packet.pcap - A single ICMPv6 packet 17 | 18 | ipv6_http.pcap 19 | - Some ipv6 packets from http communication used by IPv6packetTest.cs to 20 | verify that the checksums for IPv6 packets are calculated properly 21 | 22 | tcp.pcap 23 | - Some arbitrary tcp packets used to test the checksumming code. 24 | 25 | tcp_with_extra_bytes.pcap 26 | - A single tcp packet that has 6 extra bytes beyond the zero length tcp packet. 27 | Allows for testing that TCPPacket.TCPData returns the proper length in odd 28 | situations. 29 | 30 | ip_packet_bogus_length.pcap 31 | - A single IP packet that has an invalid total length less than the length 32 | of the header. 33 | -------------------------------------------------------------------------------- /Test/capture_files/arp_request_response.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotpcap/sharppcap/bfedf297e7410ffcf44e05d14f7fbef304f20895/Test/capture_files/arp_request_response.pcap -------------------------------------------------------------------------------- /Test/capture_files/arp_with_vlan.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotpcap/sharppcap/bfedf297e7410ffcf44e05d14f7fbef304f20895/Test/capture_files/arp_with_vlan.pcap -------------------------------------------------------------------------------- /Test/capture_files/ip_packet_bogus_length.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotpcap/sharppcap/bfedf297e7410ffcf44e05d14f7fbef304f20895/Test/capture_files/ip_packet_bogus_length.pcap -------------------------------------------------------------------------------- /Test/capture_files/ipv6_http.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotpcap/sharppcap/bfedf297e7410ffcf44e05d14f7fbef304f20895/Test/capture_files/ipv6_http.pcap -------------------------------------------------------------------------------- /Test/capture_files/ipv6_icmpv6_packet.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotpcap/sharppcap/bfedf297e7410ffcf44e05d14f7fbef304f20895/Test/capture_files/ipv6_icmpv6_packet.pcap -------------------------------------------------------------------------------- /Test/capture_files/tcp.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotpcap/sharppcap/bfedf297e7410ffcf44e05d14f7fbef304f20895/Test/capture_files/tcp.pcap -------------------------------------------------------------------------------- /Test/capture_files/tcp_with_extra_bytes.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotpcap/sharppcap/bfedf297e7410ffcf44e05d14f7fbef304f20895/Test/capture_files/tcp_with_extra_bytes.pcap -------------------------------------------------------------------------------- /Test/capture_files/test_stream.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotpcap/sharppcap/bfedf297e7410ffcf44e05d14f7fbef304f20895/Test/capture_files/test_stream.pcap -------------------------------------------------------------------------------- /Test/capture_files/udp_dns_request_response.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotpcap/sharppcap/bfedf297e7410ffcf44e05d14f7fbef304f20895/Test/capture_files/udp_dns_request_response.pcap -------------------------------------------------------------------------------- /Tutorial/sharppcap/SharpPcap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dotpcap/sharppcap/bfedf297e7410ffcf44e05d14f7fbef304f20895/Tutorial/sharppcap/SharpPcap.png -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2019 Lex Li 2 | # Copyright 2020-2021 Chris Morgan 3 | # Copyright 2020-2022 Ayoub Kaanich 4 | # SPDX-License-Identifier: MIT 5 | 6 | # Build and run tests for .NET Desktop or Windows classic desktop solutions. 7 | # Add steps that publish symbols, save build artifacts, and more: 8 | # https://docs.microsoft.com/azure/devops/pipelines/apps/windows/dot-net 9 | 10 | trigger: 11 | - master 12 | 13 | pr: 14 | autoCancel: true 15 | branches: 16 | include: 17 | - '*' # quote since "*" is a YAML reserved character 18 | 19 | jobs: 20 | - job: linux 21 | pool: 22 | vmImage: ubuntu-24.04 23 | steps: 24 | - script: sudo -E bash scripts/install-libpcap.sh 25 | - script: sudo -E bash scripts/install-tap.sh 26 | - script: sudo -E bash scripts/test.sh 27 | env: 28 | CODECOV_TOKEN: $(CODECOV_TOKEN) 29 | 30 | - job: macos 31 | pool: 32 | vmImage: macOS-14 33 | steps: 34 | - script: sudo -E bash scripts/install-libpcap.sh 35 | - script: sudo sysctl -w net.inet.udp.maxdgram=65535 36 | - script: sudo -E bash scripts/test.sh 37 | env: 38 | CODECOV_TOKEN: $(CODECOV_TOKEN) 39 | 40 | # This CI job is for testing of x86 architecture compatibility 41 | - job: windows_2022_x86 42 | pool: 43 | vmImage: windows-2022 44 | steps: 45 | - pwsh: ./scripts/Install-windows.ps1 46 | - pwsh: ./scripts/Install-npcap.ps1 47 | env: 48 | npcap_oem_key: $(npcap_oem_key) 49 | - pwsh: .\scripts\install-winpkfilter.ps1 50 | # NOTE: Remove filter when npcap has rpcapd support 51 | - script: bash scripts/test.sh --filter "TestCategory!=RemotePcap" -r win-x86 52 | env: 53 | CODECOV_TOKEN: $(CODECOV_TOKEN) 54 | 55 | - job: windows_2022_npcap 56 | pool: 57 | vmImage: windows-2022 58 | steps: 59 | - pwsh: ./scripts/Install-windows.ps1 60 | - pwsh: ./scripts/Install-npcap.ps1 61 | env: 62 | npcap_oem_key: $(npcap_oem_key) 63 | - pwsh: .\scripts\install-winpkfilter.ps1 64 | # NOTE: Remove filter when npcap has rpcapd support 65 | - script: bash scripts/test.sh --filter "TestCategory!=RemotePcap" 66 | env: 67 | CODECOV_TOKEN: $(CODECOV_TOKEN) 68 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | # Copyright 2020-2021 Ayoub Kaanich 2 | # SPDX-License-Identifier: MIT 3 | 4 | codecov: 5 | # Allow collecting coverage even if some CIs fail 6 | require_ci_to_pass: false 7 | notify: 8 | # 3 for appveyor 9 | # 3 for azure pipelines 10 | # 1 for circleci 11 | # Total = 8 12 | # Tolerate one of the services being down (worst case appveyor) 13 | after_n_builds: 3 14 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:recommended" 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | # Copyright 2023 Ayoub Kaanich 2 | # SPDX-License-Identifier: MIT 3 | reuse==5.0.2 4 | -------------------------------------------------------------------------------- /scripts/Install-npcap.ps1: -------------------------------------------------------------------------------- 1 | # Copyright 2021 Chris Morgan 2 | # SPDX-License-Identifier: MIT 3 | 4 | # Install Npcap on the machine. 5 | # Based on https://github.com/secdev/scapy/blob/master/.config/appveyor/InstallNpcap.ps1 6 | 7 | # Config: 8 | $npcap_oem_file = "npcap-1.55-oem.exe" 9 | 10 | # Note: because we need the /S option (silent), this script has two cases: 11 | # - The script is runned from a master build, then use the secure variable 'npcap_oem_key' which will be available 12 | # to decode the very recent npcap install oem file and use it 13 | # - The script is runned from a PR, then use the provided archived 0.96 version, which is the last public one to 14 | # provide support for the /S option 15 | 16 | if (Test-Path Env:npcap_oem_key){ # Key is here: on master 17 | # Unpack the key 18 | # The format of the environment variable should be 'username,password' 19 | # Disabled for now, the configured credentials are not working 20 | # $user, $pass = (Get-ChildItem Env:npcap_oem_key).Value.replace("`"", "").split(",") 21 | } 22 | if($user -And $pass){ 23 | echo "Using Npcap OEM version" 24 | $file = $PSScriptRoot+"\"+$npcap_oem_file 25 | # Download oem file using (super) secret credentials 26 | $pair = "${user}:${pass}" 27 | $encodedCreds = [System.Convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($pair)) 28 | $basicAuthValue = "Basic $encodedCreds" 29 | $headers = @{ Authorization = $basicAuthValue } 30 | $secpasswd = ConvertTo-SecureString $pass -AsPlainText -Force 31 | $credential = New-Object System.Management.Automation.PSCredential($user, $secpasswd) 32 | Invoke-WebRequest -uri (-join("https://nmap.org/npcap/oem/dist/",$npcap_oem_file)) -OutFile $file -Headers $headers -Credential $credential 33 | } else { # No key: PRs 34 | echo "Using backup 0.96" 35 | $file = $PSScriptRoot+"\npcap-0.96.exe" 36 | # Download the 0.96 file from nmap servers 37 | Invoke-WebRequest -uri "https://nmap.org/npcap/dist/npcap-0.96.exe" -OutFile $file 38 | # Now let's check its checksum 39 | $_chksum = $(CertUtil -hashfile $file SHA256)[1] -replace " ","" 40 | if ($_chksum -ne "83667e1306fdcf7f9967c10277b36b87e50ee8812e1ee2bb9443bdd065dc04a1"){ 41 | echo "Checksums does NOT match !" 42 | exit 43 | } else { 44 | echo "Checksums matches !" 45 | } 46 | } 47 | echo ('Installing: ' + $file) 48 | 49 | # Run installer 50 | Start-Process $file -ArgumentList "/loopback_support=yes /winpcap_mode /S" -wait 51 | if($?) { 52 | echo "Npcap installation completed" 53 | } 54 | -------------------------------------------------------------------------------- /scripts/install-libpcap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2021 Ayoub Kaanich 4 | # SPDX-License-Identifier: MIT 5 | 6 | # the default installation of libpcap does not have remote pcap enabled 7 | # so we need to compile our own 8 | # see https://github.com/the-tcpdump-group/libpcap/issues/795 9 | 10 | # Those are the dependencies needed to build libpcap 11 | if [[ "$OSTYPE" == "darwin"* ]]; then 12 | # Mac OSX, use https://www.macports.org/ 13 | port install bison 14 | port install flex 15 | else 16 | # Ubuntu 17 | apt-get install -y build-essential bison flex 18 | fi 19 | 20 | # clone into tmp folder 21 | rm -rf /tmp/install-libpcap 22 | 23 | # 1.9.1 is the version we tested to work 24 | git clone --depth 1 -b libpcap-1.10 https://github.com/the-tcpdump-group/libpcap.git /tmp/install-libpcap 25 | 26 | pushd /tmp/install-libpcap 27 | 28 | # remote is disabled by default, so we need to enable it 29 | ./configure --enable-remote --disable-universal 30 | 31 | # install the library 32 | make install 33 | 34 | # create the necessary links and cache 35 | # see https://www.mono-project.com/docs/advanced/pinvoke/dllnotfoundexception/ 36 | ldconfig 37 | 38 | popd 39 | -------------------------------------------------------------------------------- /scripts/install-tap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2021 Ayoub Kaanich 4 | # SPDX-License-Identifier: MIT 5 | 6 | ip tuntap add mode tap 7 | -------------------------------------------------------------------------------- /scripts/install-windows.ps1: -------------------------------------------------------------------------------- 1 | 2 | # Copyright 2022 Ayoub Kaanich 3 | # SPDX-License-Identifier: MIT 4 | 5 | choco install -y tapwindows 6 | choco install -y procdump 7 | -------------------------------------------------------------------------------- /scripts/install-winpkfilter.ps1: -------------------------------------------------------------------------------- 1 | 2 | # Copyright 2022 Ayoub Kaanich 3 | # SPDX-License-Identifier: MIT 4 | 5 | Push-Location $env:TEMP 6 | 7 | $arch = If ([Environment]::Is64BitOperatingSystem) {'x64'} Else {'x86'} 8 | $version = "3.2.32.1" 9 | $url = "https://github.com/wiresock/ndisapi/releases/download/v$version/Windows.Packet.Filter.$version.$arch.msi" 10 | 11 | echo "Downloading $url" 12 | Invoke-WebRequest $url -OutFile "WinpkFilter-$arch.msi" 13 | $process = Start-Process "WinpkFilter-$arch.msi" -ArgumentList "/norestart /quiet /l WinpkFilter-$arch.log" -PassThru -Wait 14 | Get-Content "WinpkFilter-$arch.log" 15 | 16 | Pop-Location 17 | 18 | exit $process.ExitCode 19 | -------------------------------------------------------------------------------- /scripts/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Copyright 2022 Ayoub Kaanich 4 | # SPDX-License-Identifier: MIT 5 | 6 | set -e 7 | 8 | TEST_ARGS=("$@") 9 | 10 | TEST_ARGS+=( -p:CollectCoverage=true ) 11 | TEST_ARGS+=( --blame-crash ) 12 | 13 | # select logger based on CI server 14 | 15 | if [ -n "$APPVEYOR" ] # AppVeyor 16 | then 17 | TEST_ARGS+=( --logger:Appveyor --test-adapter-path:. ) 18 | elif [ -n "$SYSTEM_TEAMFOUNDATIONCOLLECTIONURI" ] # Azure Pipelines 19 | then 20 | TEST_ARGS+=( --logger:trx ) 21 | else 22 | TEST_ARGS+=( --logger:junit --test-adapter-path:. ) 23 | fi 24 | 25 | dotnet test "${TEST_ARGS[@]}" 26 | 27 | # coverage 28 | pip install codecov-cli || python3 -m pip install codecov-cli 29 | codecovcli upload-process 30 | --------------------------------------------------------------------------------