diff --git a/.circleci/config.yml b/.circleci/config.yml index db6a0516..c6082fe4 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,10 +1,27 @@ -# Copyright 2020-2021 Chris Morgan -# SPDX-License-Identifier: MIT - version: 2.1 +parameters: + csproj-file: + type: string + default: "SharpPcap/SharpPcap.csproj" + sonar-project: + type: string + default: "Lansweeper_sharppcap" + nuget-output-file: + type: string + default: "SharpPcap/bin/Release/Lansweeper.SharpPcap.$PACKAGE_VERSION.nupkg" + nuget-output-file-static: + type: string + default: "SharpPcap/bin/Release/Lansweeper.SharpPcap.StaticLinking.$PACKAGE_VERSION.nupkg" + +executors: + node: + docker: + - image: circleci/node:12 + orbs: win: circleci/windows@5.0.0 + sonar-check: lansweeper/sonar@0.0.6 commands: report: @@ -15,64 +32,155 @@ commands: path: Test/TestResults jobs: - test-windows: + build: + executor: win/default + steps: + - checkout + - run: + name: Extract version from .csproj + command: | + $file = Get-Item << parameters.csproj-file >> + [xml]$cn = Get-Content $file + $version = $cn.Project.PropertyGroup.Version + echo "##vso[task.setvariable variable=PACKAGE_VERSION]$version" + - run: + name: Install SonarScanner for MSBuild .NET Core Global Tool + command: dotnet tool install --global dotnet-sonarscanner + - run: + name: Start SonarScanner + command: dotnet sonarscanner begin /k="<< parameters.sonar-project >>" /d:sonar.verbose=true /o:"lansweeper" /d:sonar.host.url="https://sonarcloud.io" /d:sonar.login=$Env:SONAR_TOKEN /d:sonar.language="cs" + - run: dotnet build << parameters.csproj-file >> --configuration Release + - run: + name: Upload SonarScanner results + command: dotnet sonarscanner end /d:sonar.login=$Env:SONAR_TOKEN + - persist_to_workspace: + root: . + paths: + - . + + nuget-prepare: executor: name: win/default steps: - - checkout - - run: ./scripts/install-windows.ps1 - - run: dotnet build -c Release - - run: bash scripts/test.sh --filter "TestCategory=WinDivert" - - report + - attach_workspace: + at: . + - run: + name: Create local nuget config file + command: | + $xml = " + + + + + + + + + + + " + Out-File -FilePath nuget.config -InputObject $xml -Encoding ASCII + - run: type nuget.config + - persist_to_workspace: + root: . + paths: + - . - test-ubuntu: - parameters: - libpcap: - description: How to install libpcap - type: string - machine: - image: ubuntu-2004:202201-02 + nuget-publish: + executor: + name: win/default steps: - - checkout - - run: sudo -E bash scripts/install-tap.sh - # Download and compile latest libpcap - - when: - condition: { equal: [ libpcap-script, << parameters.libpcap >> ] } - steps: - - run: sudo -E bash scripts/install-libpcap.sh - # Install libpcap from apt-get - - when: - condition: {not: { equal: [ libpcap-script, << parameters.libpcap >> ] } } - steps: - - run: sudo apt-get install << parameters.libpcap >> - - run: sudo -E bash scripts/test.sh - - run: - when: always - command: sudo chmod -R +r Test/TestResults - - report + - attach_workspace: + at: . + - run: + name: Set correct version in csproj file, build and pack it + command: | + $file = Get-Item << parameters.csproj-file >> + [xml]$cn = Get-Content $file + $cn.Project.PropertyGroup.Version="$env:PACKAGE_VERSION" + $cn.Save($file.FullName) + type ./<< parameters.csproj-file >> + - run: + name: Pack the default package + command: dotnet pack << parameters.csproj-file >> --configuration Release + - run: + name: Pack the StaticLinking package + command: dotnet pack << parameters.csproj-file >> --configuration StaticLinking --configuration Release + - run: + name: Publish the default package + command: | + dotnet nuget push << parameters.nuget-output-file >> --source "github" --api-key $env:GITHUB_TOKEN + - run: + name: Publish the StaticLinking package + command: | + dotnet nuget push << parameters.nuget-output-file-static >> --source "github" --api-key $env:GITHUB_TOKEN - test-arm: - machine: - image: ubuntu-2004:202101-01 - resource_class: arm.medium + sonar: + executor: node steps: - - checkout - - run: sudo -E bash scripts/install-tap.sh - - run: sudo apt-get install libpcap0.8 - - run: sudo -E bash scripts/test.sh - - run: - when: always - command: sudo chmod -R +r Test/TestResults - - report + - attach_workspace: + at: . + - sonar-check/get_sonar_status: + report_file: "/home/circleci/project/.sonarqube/out/.sonar/report-task.txt" workflows: version: 2 - build: + + ci_on_pr: + jobs: + - build: + context: + - lec-github-packages-rw + - SonarCloud + filters: + branches: + ignore: master + + - sonar: + context: + - SonarCloud + requires: + - build + filters: + branches: + ignore: master + + ci_and_release_master: + jobs: + - build: + context: + - lec-github-packages-rw + - SonarCloud + filters: + branches: + only: master + - nuget-prepare: + requires: + - build + context: + - lec-github-packages-rw + filters: + branches: + only: master + - nuget-publish: + requires: + - nuget-prepare + context: + - lec-github-packages-rw + # filters: + # branches: + # only: master + + run-daily-tests: + triggers: + - schedule: + cron: "0 0 * * *" + filters: + branches: + only: master + jobs: - - test-windows - - test-arm - - test-ubuntu: - name: << matrix.libpcap >> - matrix: - parameters: - libpcap: [ "libpcap-script", "libpcap-dev", "libpcap0.8" ] + - build: + context: + - lec-github-packages-rw + - SonarCloud \ No newline at end of file diff --git a/.github/workflows/dotnet-core.yml b/.github/workflows/dotnet-core.yml index 86dd38ac..79282220 100644 --- a/.github/workflows/dotnet-core.yml +++ b/.github/workflows/dotnet-core.yml @@ -26,8 +26,8 @@ jobs: run: dotnet build SharpPcap/SharpPcap.csproj - name: Test run: sudo -E bash scripts/test.sh - env: - CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} + # env: + # CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} - run: sudo chmod -R +r Test/TestResults if: always() @@ -42,27 +42,27 @@ jobs: name: artifacts path: Test/TestResults/ - - name: publish on version change - id: publish_nuget - uses: alirezanet/publish-nuget@v3.1.0 - with: - # Filepath of the project to be packaged, relative to root of repository - PROJECT_FILE_PATH: SharpPcap/SharpPcap.csproj + # - name: publish on version change + # id: publish_nuget + # uses: alirezanet/publish-nuget@v3.1.0 + # with: + # # Filepath of the project to be packaged, relative to root of repository + # PROJECT_FILE_PATH: SharpPcap/SharpPcap.csproj - # API key to authenticate with NuGet server - NUGET_KEY: ${{secrets.NUGET_API_KEY}} + # # API key to authenticate with NuGet server + # NUGET_KEY: ${{secrets.NUGET_API_KEY}} - # Flag to toggle pushing symbols along with nuget package to the server, disabled by default - INCLUDE_SYMBOLS: true + # # Flag to toggle pushing symbols along with nuget package to the server, disabled by default + # INCLUDE_SYMBOLS: true - license-check: - # We use https://github.com/fsfe/reuse-tool to ensure EVERY file has correct license and copyright info - # Either in the file itself, or in .reuse\dep5 for binary files and files that don't support comments - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: '3.10' - - run: pip install -r requirements.txt - - run: reuse lint + # license-check: + # # We use https://github.com/fsfe/reuse-tool to ensure EVERY file has correct license and copyright info + # # Either in the file itself, or in .reuse\dep5 for binary files and files that don't support comments + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v4 + # - uses: actions/setup-python@v5 + # with: + # python-version: '3.10' + # - run: pip install -r requirements.txt + # - run: reuse lint diff --git a/Directory.Build.props b/Directory.Build.props index 36935657..28e561f8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,6 +7,5 @@ SPDX-License-Identifier: MIT true full true - 8.0 diff --git a/Examples/Example3.BasicCap/Example03.BasicCap.csproj b/Examples/Example3.BasicCap/Example03.BasicCap.csproj index b8bec4e6..58129abf 100644 --- a/Examples/Example3.BasicCap/Example03.BasicCap.csproj +++ b/Examples/Example3.BasicCap/Example03.BasicCap.csproj @@ -2,6 +2,7 @@ Exe net8.0 + true diff --git a/Examples/Example3.BasicCap/Properties/PublishProfiles/lin-arm64-aot.pubxml b/Examples/Example3.BasicCap/Properties/PublishProfiles/lin-arm64-aot.pubxml new file mode 100644 index 00000000..9c1f3e72 --- /dev/null +++ b/Examples/Example3.BasicCap/Properties/PublishProfiles/lin-arm64-aot.pubxml @@ -0,0 +1,18 @@ + + + + + Release + Any CPU + .\publish\lin-arm64-aot\ + FileSystem + <_TargetId>Folder + net8.0 + linux-arm64 + true + false + true + + \ No newline at end of file diff --git a/Examples/Example3.BasicCap/Properties/PublishProfiles/lin-x64-aot.pubxml b/Examples/Example3.BasicCap/Properties/PublishProfiles/lin-x64-aot.pubxml new file mode 100644 index 00000000..fa31ee67 --- /dev/null +++ b/Examples/Example3.BasicCap/Properties/PublishProfiles/lin-x64-aot.pubxml @@ -0,0 +1,19 @@ + + + + + Release + Any CPU + .\publish\lin-x64-aot\ + FileSystem + <_TargetId>Folder + net8.0 + linux-x64 + true + false + false + true + + \ No newline at end of file diff --git a/Examples/Example3.BasicCap/Properties/PublishProfiles/lin-x64.pubxml b/Examples/Example3.BasicCap/Properties/PublishProfiles/lin-x64.pubxml new file mode 100644 index 00000000..92f1dc8e --- /dev/null +++ b/Examples/Example3.BasicCap/Properties/PublishProfiles/lin-x64.pubxml @@ -0,0 +1,18 @@ + + + + + Release + Any CPU + .\publish\lin-x64\ + FileSystem + <_TargetId>Folder + net8.0 + linux-x64 + true + true + false + + \ No newline at end of file diff --git a/Examples/Example3.BasicCap/Properties/PublishProfiles/win-x64-aot.pubxml b/Examples/Example3.BasicCap/Properties/PublishProfiles/win-x64-aot.pubxml new file mode 100644 index 00000000..f77495b0 --- /dev/null +++ b/Examples/Example3.BasicCap/Properties/PublishProfiles/win-x64-aot.pubxml @@ -0,0 +1,19 @@ + + + + + Release + Any CPU + .\publish\win-x64-aot\ + FileSystem + <_TargetId>Folder + net8.0 + win-x64 + true + false + false + true + + \ No newline at end of file diff --git a/Examples/Example3.BasicCap/Properties/PublishProfiles/win-x64.pubxml b/Examples/Example3.BasicCap/Properties/PublishProfiles/win-x64.pubxml new file mode 100644 index 00000000..a829582b --- /dev/null +++ b/Examples/Example3.BasicCap/Properties/PublishProfiles/win-x64.pubxml @@ -0,0 +1,18 @@ + + + + + Release + Any CPU + .\publish\win-x64\ + FileSystem + <_TargetId>Folder + net8.0 + win-x64 + true + true + false + + \ No newline at end of file diff --git a/Examples/WinformsExample/WinformsExample.csproj b/Examples/WinformsExample/WinformsExample.csproj index 175daa6b..55833830 100644 --- a/Examples/WinformsExample/WinformsExample.csproj +++ b/Examples/WinformsExample/WinformsExample.csproj @@ -1,13 +1,10 @@  WinExe - net48 + net8.0-windows + true true - - - - diff --git a/README.md b/README.md index 304a3b5c..823bd233 100644 --- a/README.md +++ b/README.md @@ -50,8 +50,16 @@ For packet dissection and creation, see [Packet.Net](https://github.com/chmorgan * .NET Core 3 and .NET Framework support - +# Publishing to nuget package +Change the following lines in the config.yml file to automatically trigger a publish of the nuget package: + +Change the version here => + nuget-output-file: + type: string + default: "SharpPcap/bin/Release/Lansweeper.SharpPcap.*.*.*.nupkg" +And here => + $env:package_version = "*.*.*" # Examples See the [Examples](https://github.com/chmorgan/sharppcap/tree/master/Examples) folder for a range of full example projects using SharpPcap diff --git a/SharpPcap.sln b/SharpPcap.sln index d2009df9..5f242eb4 100644 --- a/SharpPcap.sln +++ b/SharpPcap.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29025.244 +# Visual Studio Version 17 +VisualStudioVersion = 17.12.35527.113 d17.12 MinimumVisualStudioVersion = 10.0.40219.1 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example03.BasicCap", "Examples\Example3.BasicCap\Example03.BasicCap.csproj", "{2B5462B9-068B-46E8-B139-E3B9211A48B1}" EndProject @@ -45,6 +45,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ProjectSection(SolutionItems) = preProject .gitattributes = .gitattributes .gitignore = .gitignore + .circleci\config.yml = .circleci\config.yml LICENSE = LICENSE README.md = README.md EndProjectSection diff --git a/SharpPcap/ARP.cs b/SharpPcap/ARP.cs index 37f512a0..3ea2ecd7 100644 --- a/SharpPcap/ARP.cs +++ b/SharpPcap/ARP.cs @@ -14,7 +14,7 @@ namespace SharpPcap /// public class ARP { - private readonly PcapInterface pcapInterface; + private readonly IPcapInterface pcapInterface; /// /// Constructs a new ARP Resolver diff --git a/SharpPcap/LibPcap/BpfProgram.cs b/SharpPcap/LibPcap/BpfProgram.cs index a017db47..c45411c2 100644 --- a/SharpPcap/LibPcap/BpfProgram.cs +++ b/SharpPcap/LibPcap/BpfProgram.cs @@ -87,7 +87,7 @@ public static BpfProgram Create(LinkLayers linktype, string filter, int optimize private BpfProgram() : base(true) { - var bpfProgram = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PcapUnmanagedStructures.bpf_program))); + var bpfProgram = Marshal.AllocHGlobal(Marshal.SizeOf()); SetHandle(bpfProgram); } diff --git a/SharpPcap/LibPcap/ILibPcapLiveDevice.cs b/SharpPcap/LibPcap/ILibPcapLiveDevice.cs new file mode 100644 index 00000000..b9bf787c --- /dev/null +++ b/SharpPcap/LibPcap/ILibPcapLiveDevice.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.ObjectModel; + +namespace SharpPcap.LibPcap +{ + public interface ILibPcapLiveDevice : ILiveDevice + { + + /// + /// Addresses that represent this device + /// + ReadOnlyCollection Addresses { get; } + + /// + /// Interface flags, see pcap_findalldevs() man page for more info + /// + uint Flags { get; } + + /// + /// True if device is a loopback interface, false if not + /// + bool Loopback { get; } + + /// + /// Set/Get Non-Blocking Mode. returns allways false for savefiles. + /// + bool NonBlockingMode { get; set; } + + /// + /// Low level pcap device values + /// + IPcapInterface Interface { get; } + + /// + /// Return a value indicating if this adapter is opened + /// + bool Opened { get; } + + /// + /// The underlying pcap device handle + /// + PcapHandle Handle { get; } + + /// + /// Override the default ToString() implementation + /// + /// + /// A + /// + string ToString(); + + /// + /// Synchronously captures packets on this network device. This method will block + /// until capturing is finished. + /// + /// The number of packets to be captured. + /// -1 means capture indefiniately + void Capture(int packetCount); + + /// + /// Gets pointers to the next PCAP header and packet data. + /// Data is only valid until next call to GetNextPacketNative. + /// + /// Advanced use only. Intended to allow unmanaged code to avoid the overhead of + /// marshalling PcapHeader and packet contents to allocated memory. + /// + /// + /// See https://www.tcpdump.org/manpages/pcap_next_ex.3pcap.html + /// + int GetNextPacketPointers(ref IntPtr header, ref IntPtr data); + + } +} \ No newline at end of file diff --git a/SharpPcap/LibPcap/IPcapAddress.cs b/SharpPcap/LibPcap/IPcapAddress.cs new file mode 100644 index 00000000..a85d57c7 --- /dev/null +++ b/SharpPcap/LibPcap/IPcapAddress.cs @@ -0,0 +1,33 @@ +namespace SharpPcap.LibPcap +{ + public interface IPcapAddress + { + /// + /// The address value of this PcapAddress, null if none is present + /// + Sockaddr Addr { get; } + + /// + /// Netmask of this PcapAddress, null if none is present + /// + Sockaddr Netmask { get; } + + /// + /// Broadcast address of this PcapAddress, null if none is present + /// + Sockaddr Broadaddr { get; } + + /// + /// Destination address, null if the interface isn't a point-to-point interface + /// + Sockaddr Dstaddr { get; } + + /// + /// ToString override + /// + /// + /// A + /// + string ToString(); + } +} \ No newline at end of file diff --git a/SharpPcap/LibPcap/IPcapInterface.cs b/SharpPcap/LibPcap/IPcapInterface.cs new file mode 100644 index 00000000..1167a63f --- /dev/null +++ b/SharpPcap/LibPcap/IPcapInterface.cs @@ -0,0 +1,68 @@ +using System.Collections.Generic; +using System.Net; +using System.Net.NetworkInformation; + +namespace SharpPcap.LibPcap +{ + public interface IPcapInterface + { + /// + /// Name of the interface. Used internally when passed to pcap_open_live() + /// + string Name { get; } + + /// + /// Human readable interface name derived from System.Net.NetworkInformation.NetworkInterface.Name + /// + string FriendlyName { get; } + + /// + /// Text description of the interface as given by pcap/npcap + /// + string Description { get; } + + /// + /// Gateway address of this device + /// NOTE: May only be available on Windows + /// + List GatewayAddresses { get; } + + /// + /// Addresses associated with this device + /// + List Addresses { get; set; } + + /// + /// Pcap interface flags + /// + uint Flags { get; set; } + + /// + /// MacAddress of the interface + /// + PhysicalAddress MacAddress { get; } + + /// + /// Timestamps supported by this device + /// + /// + /// + /// Note: Live devices can have supported timestamps but offline devices + /// (such as file readers etc) do not. See https://www.tcpdump.org/manpages/pcap-tstamp.7.html + /// + System.Collections.Generic.List TimestampsSupported { get; } + + /// + /// ToString override + /// + /// + /// A + /// + string ToString(); + + /// + /// Credentials to use in case of remote pcap + /// + RemoteAuthentication Credentials { get; } + } +} \ No newline at end of file diff --git a/SharpPcap/LibPcap/LibPcapLiveDevice.cs b/SharpPcap/LibPcap/LibPcapLiveDevice.cs index 6e9dc65a..949f0b9e 100644 --- a/SharpPcap/LibPcap/LibPcapLiveDevice.cs +++ b/SharpPcap/LibPcap/LibPcapLiveDevice.cs @@ -14,14 +14,14 @@ namespace SharpPcap.LibPcap /// /// Capture live packets from a network device /// - public class LibPcapLiveDevice : PcapDevice, ILiveDevice + public class LibPcapLiveDevice : PcapDevice, ILibPcapLiveDevice { /// /// Constructs a new PcapDevice based on a 'pcapIf' struct /// /// A 'pcapIf' struct representing /// the pcap device - public LibPcapLiveDevice(PcapInterface pcapIf) + public LibPcapLiveDevice(IPcapInterface pcapIf) { m_pcapIf = pcapIf; } @@ -44,42 +44,27 @@ protected LibPcapLiveDevice() /// /// Gets the pcap name of this network device /// - public override string Name - { - get { return m_pcapIf.Name; } - } + public override string Name => m_pcapIf.Name; /// /// Addresses that represent this device /// - public virtual ReadOnlyCollection Addresses - { - get { return new ReadOnlyCollection(m_pcapIf.Addresses); } - } + public virtual ReadOnlyCollection Addresses => new ReadOnlyCollection(m_pcapIf.Addresses); /// /// Gets the pcap description of this device /// - public override string Description - { - get { return m_pcapIf.Description; } - } + public override string Description => m_pcapIf.Description; /// /// Interface flags, see pcap_findalldevs() man page for more info /// - public virtual uint Flags - { - get { return m_pcapIf.Flags; } - } + public virtual uint Flags => m_pcapIf.Flags; /// /// True if device is a loopback interface, false if not /// - public virtual bool Loopback - { - get { return (Flags & Pcap.PCAP_IF_LOOPBACK) == 1; } - } + public virtual bool Loopback => (Flags & Pcap.PCAP_IF_LOOPBACK) == 1; /// /// Open the device. To start capturing call the 'StartCapture' function @@ -165,7 +150,7 @@ public override void Open(DeviceConfiguration configuration) immediateMode = null; try { - Handle = LibPcapSafeNativeMethods.pcap_open( + Handle = LibPcapSafeNativeMethods.pcap_open_live( Name, // name of the device configuration.Snaplen, // portion of the packet to capture. (short)mode, // flags diff --git a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs index 3c6fe3ff..11af9311 100644 --- a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs +++ b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs @@ -17,12 +17,16 @@ namespace SharpPcap.LibPcap [SuppressUnmanagedCodeSecurity] internal static partial class LibPcapSafeNativeMethods { +#if STATIC_LINKING + private const string PCAP_DLL = "libpcap"; +#else // NOTE: For mono users on non-windows platforms a .config file is used to map // the windows dll name to the unix/mac library name // This file is called $assembly_name.dll.config and is placed in the // same directory as the assembly // See http://www.mono-project.com/Interop_with_Native_Libraries#Library_Names private const string PCAP_DLL = "wpcap"; +#endif [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] internal extern static int pcap_init( @@ -48,7 +52,7 @@ out ErrorBuffer /* char* */ errbuf internal extern static void pcap_freealldevs(IntPtr /* pcap_if_t * */ alldevs); [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] - internal extern static PcapHandle /* pcap_t* */ pcap_open( + internal extern static PcapHandle /* pcap_t* */ pcap_open_live( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] string dev, int packetLen, int flags, diff --git a/SharpPcap/LibPcap/PcapAddress.cs b/SharpPcap/LibPcap/PcapAddress.cs index 857a5b56..ceb0bd3e 100755 --- a/SharpPcap/LibPcap/PcapAddress.cs +++ b/SharpPcap/LibPcap/PcapAddress.cs @@ -11,7 +11,7 @@ namespace SharpPcap.LibPcap /// /// Managed representation of the unmanaged pcap_addr structure /// - public class PcapAddress + public class PcapAddress : IPcapAddress { /// /// The address value of this PcapAddress, null if none is present diff --git a/SharpPcap/LibPcap/PcapDevice.cs b/SharpPcap/LibPcap/PcapDevice.cs index 0b2b20c7..f72f0b05 100644 --- a/SharpPcap/LibPcap/PcapDevice.cs +++ b/SharpPcap/LibPcap/PcapDevice.cs @@ -18,7 +18,7 @@ public abstract partial class PcapDevice : ICaptureDevice /// /// Low level interface object that contains device specific information /// - protected PcapInterface m_pcapIf; + protected IPcapInterface m_pcapIf; /// /// Number of packets that this adapter should capture @@ -50,20 +50,14 @@ public abstract partial class PcapDevice : ICaptureDevice /// /// Low level pcap device values /// - public PcapInterface Interface - { - get { return m_pcapIf; } - } + public IPcapInterface Interface => m_pcapIf; private PacketDotNet.LinkLayers linkType; /// /// Return a value indicating if this adapter is opened /// - public virtual bool Opened - { - get { return !(Handle.IsInvalid || Handle.IsClosed); } - } + public virtual bool Opened => !(Handle.IsInvalid || Handle.IsClosed); /// /// The file descriptor obtained from pcap_fileno @@ -94,10 +88,7 @@ internal static string GetLastError(PcapHandle deviceHandle) /// /// The last pcap error associated with this pcap device /// - public virtual string LastError - { - get { return GetLastError(Handle); } - } + public virtual string LastError => GetLastError(Handle); /// /// Link type in terms of PacketDotNet.LinkLayers @@ -163,13 +154,7 @@ public virtual void Close() /// /// Mac address of the physical device /// - public virtual System.Net.NetworkInformation.PhysicalAddress MacAddress - { - get - { - return Interface.MacAddress; - } - } + public virtual System.Net.NetworkInformation.PhysicalAddress MacAddress => Interface.MacAddress; /// /// Notify the OnPacketArrival delegates about a newly captured packet @@ -511,9 +496,9 @@ public override string ToString() /// public static IEnumerable GetSequence(ICaptureDevice dev, bool maskExceptions = true) { + PacketCapture e; try { - PacketCapture e; dev.Open(); while (true) { diff --git a/SharpPcap/LibPcap/PcapDeviceCaptureLoop.cs b/SharpPcap/LibPcap/PcapDeviceCaptureLoop.cs index 8f395144..80ffc046 100644 --- a/SharpPcap/LibPcap/PcapDeviceCaptureLoop.cs +++ b/SharpPcap/LibPcap/PcapDeviceCaptureLoop.cs @@ -159,7 +159,9 @@ protected virtual void CaptureThread(CancellationToken cancellationToken) continue; } + #pragma warning disable S3869 // "SafeHandle.DangerousGetHandle" should not be called int res = LibPcapSafeNativeMethods.pcap_dispatch(handle, m_pcapPacketCount, Callback, handle.DangerousGetHandle()); + #pragma warning restore S3869 // "SafeHandle.DangerousGetHandle" should not be called // pcap_dispatch() returns the number of packets read or, a status value if the value // is negative @@ -176,7 +178,9 @@ protected virtual void CaptureThread(CancellationToken cancellationToken) // from causing premature exiting from the capture loop we only consider // exhausted events to cause an escape from the loop when they are from // offline devices, ie. files read from disk + #pragma warning disable S3060 if (this is CaptureReaderDevice) + #pragma warning restore S3060 { SendCaptureStoppedEvent(CaptureStoppedEventStatus.CompletedWithoutError); return; diff --git a/SharpPcap/LibPcap/PcapInterface.cs b/SharpPcap/LibPcap/PcapInterface.cs index caa5dceb..06398a2d 100644 --- a/SharpPcap/LibPcap/PcapInterface.cs +++ b/SharpPcap/LibPcap/PcapInterface.cs @@ -20,7 +20,7 @@ namespace SharpPcap.LibPcap /// device memory is freed, so instead convert the unmanaged structure /// to a managed one to avoid this issue /// - public class PcapInterface + public class PcapInterface : IPcapInterface { /// /// Name of the interface. Used internally when passed to pcap_open_live() @@ -46,17 +46,17 @@ public class PcapInterface /// /// Addresses associated with this device /// - public List Addresses { get; internal set; } + public List Addresses { get; set; } /// /// Credentials to use in case of remote pcap /// - internal RemoteAuthentication Credentials { get; } + public RemoteAuthentication Credentials { get; internal set; } /// /// Pcap interface flags /// - public uint Flags { get; internal set; } + public uint Flags { get; set; } /// /// MacAddress of the interface @@ -68,7 +68,7 @@ internal PcapInterface(pcap_if pcapIf, NetworkInterface networkInterface, Remote Name = pcapIf.Name; Description = pcapIf.Description; Flags = pcapIf.Flags; - Addresses = new List(); + Addresses = new List(); GatewayAddresses = new List(); Credentials = credentials; @@ -118,8 +118,10 @@ internal PcapInterface(pcap_if pcapIf, NetworkInterface networkInterface, Remote PhysicalAddress mac = networkInterface.GetPhysicalAddress(); if (MacAddress == null && mac != null) { - PcapAddress pcapAddress = new PcapAddress(); - pcapAddress.Addr = new Sockaddr(mac); + PcapAddress pcapAddress = new PcapAddress + { + Addr = new Sockaddr(mac) + }; Addresses.Add(pcapAddress); if (pcapAddress.Addr.hardwareAddress.GetAddressBytes().Length != 0) { @@ -160,7 +162,7 @@ public override string ToString() } sb.AppendFormat("Description: {0}\n", Description); - foreach (PcapAddress addr in Addresses) + foreach (IPcapAddress addr in Addresses) { sb.AppendFormat("Addresses:\n{0}\n", addr); } diff --git a/SharpPcap/LibPcap/PcapStatistics.cs b/SharpPcap/LibPcap/PcapStatistics.cs index 5ea469f4..e6ef962c 100644 --- a/SharpPcap/LibPcap/PcapStatistics.cs +++ b/SharpPcap/LibPcap/PcapStatistics.cs @@ -43,12 +43,12 @@ internal PcapStatistics(PcapHandle pcap_t) if (Environment.OSVersion.Platform == PlatformID.Unix) { // allocate memory for the struct - stat = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PcapUnmanagedStructures.pcap_stat_unix))); + stat = Marshal.AllocHGlobal(Marshal.SizeOf()); } else { // allocate memory for the struct - stat = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(PcapUnmanagedStructures.pcap_stat_windows))); + stat = Marshal.AllocHGlobal(Marshal.SizeOf()); } // retrieve the stats @@ -73,28 +73,26 @@ internal PcapStatistics(PcapHandle pcap_t) // marshal the unmanaged memory into an object of the proper type if (Environment.OSVersion.Platform == PlatformID.Unix) { - var managedStat = (PcapUnmanagedStructures.pcap_stat_unix)Marshal.PtrToStructure(stat, - typeof(PcapUnmanagedStructures.pcap_stat_unix)); + var managedStat = Marshal.PtrToStructure< PcapUnmanagedStructures.pcap_stat_unix>(stat); // copy the values - this.ReceivedPackets = (uint)managedStat.ps_recv.ToInt64(); - this.DroppedPackets = (uint)managedStat.ps_drop.ToInt64(); + ReceivedPackets = (uint)managedStat.ps_recv.ToInt64(); + DroppedPackets = (uint)managedStat.ps_drop.ToInt64(); // this.InterfaceDroppedPackets = (uint)managedStat.ps_ifdrop; } else { - var managedStat = (PcapUnmanagedStructures.pcap_stat_windows)Marshal.PtrToStructure(stat, - typeof(PcapUnmanagedStructures.pcap_stat_windows)); + var managedStat = Marshal.PtrToStructure(stat); // copy the values - this.ReceivedPackets = (uint)managedStat.ps_recv; - this.DroppedPackets = (uint)managedStat.ps_drop; + ReceivedPackets = managedStat.ps_recv; + DroppedPackets = managedStat.ps_drop; // this.InterfaceDroppedPackets = (uint)managedStat.ps_ifdrop; } // NOTE: Not supported on unix or npcap, no need to // put a bogus value in this field - this.InterfaceDroppedPackets = 0; + InterfaceDroppedPackets = 0; // free the stats Marshal.FreeHGlobal(stat); diff --git a/SharpPcap/README.md b/SharpPcap/README.md new file mode 100644 index 00000000..38a0d5c4 --- /dev/null +++ b/SharpPcap/README.md @@ -0,0 +1,75 @@ +# Lansweeper SharpPcap + +This is a fork of the original SharpPcap project, which is a cross-platform packet capture framework for the .NET environment. +The original project can be found [here](https://github.com/dotpcap/sharppcap) + +This fork is maintained by Lansweeper and can be found [here](https://github.com/Lansweeper/sharppcap) + +> This is the default version. For the version with static linking, see `Lansweeper.SharpPcap.StaticLinking`. + +## Changes to the original project +- Allow for AoT compilation +- Added support for ARM64 +- Better abstractions and better testability +- Removed netstandard2.0 support + +SharpPcap is a cross-platform (Windows, Mac, Linux) packet capture framework for the .NET environment. +It provides an API for capturing, injecting, analyzing, and building packets using any .NET language such as C# and VB.NET. + +## Features + +- Cross-platform support (Windows, Mac, Linux) +- Capture and inject packets +- Analyze and build packets +- Easy-to-use API + +## Installation + +You can install the package via NuGet Package Manager: + + +## Usage + +Here is a simple example of how to use SharpPcap: + +```cs +using SharpPcap; +using PacketDotNet; + + +// List available devices +var devices = CaptureDeviceList.Instance; +foreach (var dev in devices) { + Console.WriteLine($"{dev.Name} - {dev.Description}"); +} + +// Open the first device +var device = devices[0]; +device.Open(); + +// Capture packets +device.OnPacketArrival += new PacketArrivalEventHandler(Device_OnPacketArrival); +device.StartCapture(); + +Console.WriteLine("Press any key to stop..."); +Console.ReadKey(); + +device.StopCapture(); +device.Close(); + + +static void Device_OnPacketArrival(object sender, CaptureEventArgs e) +{ + var packet = Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data); + Console.WriteLine(packet.ToString()); +} + +``` + +## License + +This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details. + +## TODO +- Nullability +- replace [DllImport] with [ImportLibrary] \ No newline at end of file diff --git a/SharpPcap/README_StaticLinking.md b/SharpPcap/README_StaticLinking.md new file mode 100644 index 00000000..76854eda --- /dev/null +++ b/SharpPcap/README_StaticLinking.md @@ -0,0 +1,79 @@ +# Lansweeper SharpPcap + +This is a fork of the original SharpPcap project, which is a cross-platform packet capture framework for the .NET environment. +The original project can be found [here](https://github.com/dotpcap/sharppcap) + +This fork is maintained by Lansweeper and can be found [here](https://github.com/Lansweeper/sharppcap) + +> This is the a special version to support static linking on UNIX. For the default version with dynamic linking, see `Lansweeper.SharpPcap`. + +## Changes to the original project +- Allow for AoT compilation +- Added support for ARM64 +- Better abstractions and better testability +- Removed netstandard2.0 support + +SharpPcap is a cross-platform (Windows, Mac, Linux) packet capture framework for the .NET environment. +It provides an API for capturing, injecting, analyzing, and building packets using any .NET language such as C# and VB.NET. + +## Features + +- Cross-platform support (Windows, Mac, Linux) +- Capture and inject packets +- Analyze and build packets +- Easy-to-use API + +## Installation + +You can install the package via NuGet Package Manager: + + +## Usage + +Here is a simple example of how to use SharpPcap: + +```cs +using SharpPcap; +using PacketDotNet; + + +// List available devices +var devices = CaptureDeviceList.Instance; +foreach (var dev in devices) { + Console.WriteLine($"{dev.Name} - {dev.Description}"); +} + +// Open the first device +var device = devices[0]; +device.Open(); + +// Capture packets +device.OnPacketArrival += new PacketArrivalEventHandler(Device_OnPacketArrival); +device.StartCapture(); + +Console.WriteLine("Press any key to stop..."); +Console.ReadKey(); + +device.StopCapture(); +device.Close(); + + +static void Device_OnPacketArrival(object sender, CaptureEventArgs e) +{ + var packet = Packet.ParsePacket(e.Packet.LinkLayerType, e.Packet.Data); + Console.WriteLine(packet.ToString()); +} + +``` + +## Documentation + +For more detailed documentation, please visit the [project's GitHub page](https://github.com/Lansweeper/sharppcap). + +## License + +This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details. + +## TODO +- Nullability +- replace [DllImport] with [ImportLibrary] \ No newline at end of file diff --git a/SharpPcap/SharpPcap.csproj b/SharpPcap/SharpPcap.csproj index 07c6d0e8..40d913d8 100644 --- a/SharpPcap/SharpPcap.csproj +++ b/SharpPcap/SharpPcap.csproj @@ -6,39 +6,50 @@ Copyright 2008-2011 Chris Morgan SPDX-License-Identifier: MIT --> - - netstandard2.0;net8.0 - 6.3.0 - A packet capture framework for .NET - Tamir Gal, Chris Morgan and others - https://github.com/chmorgan/sharppcap - false - https://github.com/chmorgan/sharppcap - true - true - true - snupkg - Tamir Gal, Chris Morgan and others - - SharpPcap is a cross-platform(Windows, Mac, Linux) packet capture framework for the .NET environment. - It provides an API for capturing, injecting, analyzing and building packets using any .NET language such as C# and VB.NET. - - MIT - true - true - - - true - - - - - - - - - - <_Parameter1>Test - - + + net8.0 + 10.0.0-beta + Lansweeper.SharpPcap + Lansweeper + Lansweeper SharpPcap + Lansweeper SharpPcap + A packet capture framework for .NET + Tamir Gal, Chris Morgan and others + https://github.com/Lansweeper/sharppcap + false + https://github.com/Lansweeper/sharppcap + true + true + true + snupkg + Tamir Gal, Chris Morgan and others + + SharpPcap is a cross-platform(Windows, Mac, Linux) packet capture framework for the .NET environment. + It provides an API for capturing, injecting, analyzing and building packets using any .NET language such as C# and VB.NET. + + MIT + README.md + true + true + true + true + + + + STATIC_LINKING + Lansweeper.SharpPcap.StaticLinking + $(PackageVersion) + README_StaticLinking.md + + + + + + + + + + <_Parameter1>Test + + diff --git a/SharpPcap/Statistics/StatisticsDevice.cs b/SharpPcap/Statistics/StatisticsDevice.cs index dcd440f7..19e5b31f 100644 --- a/SharpPcap/Statistics/StatisticsDevice.cs +++ b/SharpPcap/Statistics/StatisticsDevice.cs @@ -24,7 +24,7 @@ public class StatisticsDevice : IPcapDevice /// /// A 'pcapIf' struct representing /// the pcap device - public StatisticsDevice(PcapInterface pcapIf) + public StatisticsDevice(IPcapInterface pcapIf) { LiveDevice = new LibPcapLiveDevice(pcapIf); } diff --git a/Test/CaptureFileReaderDeviceTest.cs b/Test/CaptureFileReaderDeviceTest.cs index 55793ef8..7d16d1d3 100644 --- a/Test/CaptureFileReaderDeviceTest.cs +++ b/Test/CaptureFileReaderDeviceTest.cs @@ -8,6 +8,8 @@ using PacketDotNet; using System.IO; using System.Collections.Generic; +using System.Globalization; +using System.Threading; namespace Test { @@ -31,6 +33,7 @@ public void CaptureNonExistant() [TestCase(TimestampResolution.Microsecond, "1186341404.189852s")] public void CaptureTimestampResolution(TimestampResolution resolution, string timeval) { + Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture; var filename = "ipv6_http.pcap"; using var device = new CaptureFileReaderDevice(TestHelper.GetFile(filename)); var configuration = new DeviceConfiguration diff --git a/Test/MemorySafetyTests.cs b/Test/MemorySafetyTests.cs index dca5a8a3..f517abe1 100644 --- a/Test/MemorySafetyTests.cs +++ b/Test/MemorySafetyTests.cs @@ -24,7 +24,7 @@ namespace Test public class MemorySafetyTests { - private readonly PcapInterface TestInterface = GetPcapDevice().Interface; + private readonly IPcapInterface TestInterface = GetPcapDevice().Interface; [Test] [Parallelizable(ParallelScope.Children)] diff --git a/Test/Test.csproj b/Test/Test.csproj index ceb77db9..d3819471 100644 --- a/Test/Test.csproj +++ b/Test/Test.csproj @@ -9,7 +9,6 @@ SPDX-License-Identifier: MIT true net8.0 - $(TargetFrameworks);net48 opencover diff --git a/catalog-info.repo.yaml b/catalog-info.repo.yaml new file mode 100644 index 00000000..6742354c --- /dev/null +++ b/catalog-info.repo.yaml @@ -0,0 +1,11 @@ +apiVersion: lansweeper.com/v1alpha1 +kind: Repository +metadata: + annotations: + github.com/project-slug: Lansweeper/sharppcap + description: Official repository - Fully managed, cross platform (Windows, Mac, + Linux) .NET library for capturing packets + name: sharppcap +spec: + lifecycle: stable + owner: unknown \ No newline at end of file diff --git a/scripts/test.sh b/scripts/test.sh index 7c5d769b..9da749ce 100644 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -24,6 +24,6 @@ fi dotnet test "${TEST_ARGS[@]}" -# coverage -pip install codecov-cli || python3 -m pip install codecov-cli -codecovcli upload-process +# # coverage +# pip install codecov-cli || python3 -m pip install codecov-cli +# codecovcli upload-process