From a3b097e5709d9f901da0b7c236c6edcc77feed73 Mon Sep 17 00:00:00 2001 From: Ayoub Kaanich Date: Sun, 15 Sep 2024 22:32:44 +0200 Subject: [PATCH 1/6] Fix marshalling of StringBuilder errors --- .../LibPcapSafeNativeMethods.Encoding.cs | 23 +++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs index 693a396d..9d65d437 100644 --- a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs +++ b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs @@ -75,7 +75,7 @@ public void CleanUpNativeData(IntPtr nativeData) { if (FreeOnClean) { - Marshal.FreeHGlobal(nativeData); + Marshal.FreeHGlobal(nativeData - IntPtr.Size); } } @@ -92,6 +92,7 @@ public IntPtr MarshalManagedToNative(object managedObj) } byte[] bytes = null; var byteCount = 0; + IntPtr gcHandle = IntPtr.Zero; if (managedObj is string str) { bytes = StringEncoding.GetBytes(str); @@ -101,14 +102,19 @@ public IntPtr MarshalManagedToNative(object managedObj) if (managedObj is StringBuilder builder) { bytes = StringEncoding.GetBytes(builder.ToString()); - byteCount = StringEncoding.GetMaxByteCount(builder.Capacity) + 1; + byteCount = Math.Max(bytes.Length, builder.Capacity) + 1; + gcHandle = GCHandle.ToIntPtr(GCHandle.Alloc(managedObj)); } if (bytes is null) { throw new ArgumentException("The input argument is not a supported type."); } - var ptr = Marshal.AllocHGlobal(byteCount); + // The problem is that we need a reference to the StringBuilder in MarshalNativeToManaged + // So we get a pointer to it with GCHandle, and put it as prefix of the pointer we return + var ptr = Marshal.AllocHGlobal(byteCount + IntPtr.Size); + Marshal.WriteIntPtr(ptr, gcHandle); + ptr += IntPtr.Size; Marshal.Copy(bytes, 0, ptr, bytes.Length); // Put zero string termination Marshal.WriteByte(ptr + bytes.Length, 0); @@ -121,13 +127,22 @@ public unsafe object MarshalNativeToManaged(IntPtr nativeData) { return null; } + var gcHandlePtr = Marshal.ReadIntPtr(nativeData - IntPtr.Size); var bytes = (byte*)nativeData; var nbBytes = 0; while (*(bytes + nbBytes) != 0) { nbBytes++; } - return StringEncoding.GetString(bytes, nbBytes); + var stringData = StringEncoding.GetString(bytes, nbBytes); + if (gcHandlePtr != IntPtr.Zero) + { + var gcHandle = GCHandle.FromIntPtr(gcHandlePtr); + var stringBuilder = (StringBuilder)gcHandle.Target; + gcHandle.Free(); + stringBuilder.Append(stringData); + } + return stringData; } } } From a7db60e45da548408c1b6275e154ea2806de99c1 Mon Sep 17 00:00:00 2001 From: Ayoub Kaanich Date: Sun, 15 Sep 2024 23:09:35 +0200 Subject: [PATCH 2/6] Move StringBuilder logic to PcapStringBuilderMarshaler --- .../LibPcapSafeNativeMethods.Encoding.cs | 100 ++++++++++++------ .../LibPcapSafeNativeMethods.Interop.cs | 22 ++-- 2 files changed, 77 insertions(+), 45 deletions(-) diff --git a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs index 9d65d437..98588a58 100644 --- a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs +++ b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs @@ -48,6 +48,66 @@ private static Encoding ConfigureStringEncoding() return Encoding.GetEncoding(0); } + /// + /// Helper class to marshall StringBuilder depending on encoding used by Libpcap + /// + private class PcapStringBuilderMarshaler : ICustomMarshaler + { + + public static ICustomMarshaler GetInstance(string cookie) + { + return new PcapStringBuilderMarshaler(); + } + + public void CleanUpManagedData(object managedObj) + { + // Nothing to clean + } + + public void CleanUpNativeData(IntPtr nativeData) + { + // Nothing to clean + } + + public int GetNativeDataSize() + { + return -1; + } + + public IntPtr MarshalManagedToNative(object managedObj) + { + var builder = (StringBuilder)managedObj; + var byteCount = builder.Capacity + 1; + var gcHandle = GCHandle.ToIntPtr(GCHandle.Alloc(managedObj)); + + // The problem is that we need a reference to the StringBuilder in MarshalNativeToManaged + // So we get a pointer to it with GCHandle, and put it as prefix of the pointer we return + var ptr = Marshal.AllocHGlobal(byteCount + IntPtr.Size); + Marshal.WriteIntPtr(ptr, gcHandle); + ptr += IntPtr.Size; + return ptr; + } + + public unsafe object MarshalNativeToManaged(IntPtr nativeData) + { + var gcHandlePtr = Marshal.ReadIntPtr(nativeData - IntPtr.Size); + var bytes = (byte*)nativeData; + var nbBytes = 0; + while (*(bytes + nbBytes) != 0) + { + nbBytes++; + } + var stringData = StringEncoding.GetString(bytes, nbBytes); + + var gcHandle = GCHandle.FromIntPtr(gcHandlePtr); + var stringBuilder = (StringBuilder)gcHandle.Target; + gcHandle.Free(); + stringBuilder.Append(stringData); + + return null; + } + } + /// /// Helper class to marshall string depending on encoding used by Libpcap /// @@ -75,7 +135,7 @@ public void CleanUpNativeData(IntPtr nativeData) { if (FreeOnClean) { - Marshal.FreeHGlobal(nativeData - IntPtr.Size); + Marshal.FreeHGlobal(nativeData); } } @@ -90,31 +150,11 @@ public IntPtr MarshalManagedToNative(object managedObj) { return IntPtr.Zero; } - byte[] bytes = null; - var byteCount = 0; - IntPtr gcHandle = IntPtr.Zero; - if (managedObj is string str) - { - bytes = StringEncoding.GetBytes(str); - byteCount = bytes.Length + 1; - } - - if (managedObj is StringBuilder builder) - { - bytes = StringEncoding.GetBytes(builder.ToString()); - byteCount = Math.Max(bytes.Length, builder.Capacity) + 1; - gcHandle = GCHandle.ToIntPtr(GCHandle.Alloc(managedObj)); - } - - if (bytes is null) - { - throw new ArgumentException("The input argument is not a supported type."); - } + var str = (string)managedObj; + var bytes = StringEncoding.GetBytes(str); // The problem is that we need a reference to the StringBuilder in MarshalNativeToManaged // So we get a pointer to it with GCHandle, and put it as prefix of the pointer we return - var ptr = Marshal.AllocHGlobal(byteCount + IntPtr.Size); - Marshal.WriteIntPtr(ptr, gcHandle); - ptr += IntPtr.Size; + var ptr = Marshal.AllocHGlobal(bytes.Length + 1); Marshal.Copy(bytes, 0, ptr, bytes.Length); // Put zero string termination Marshal.WriteByte(ptr + bytes.Length, 0); @@ -127,22 +167,14 @@ public unsafe object MarshalNativeToManaged(IntPtr nativeData) { return null; } - var gcHandlePtr = Marshal.ReadIntPtr(nativeData - IntPtr.Size); + var gcHandlePtr = Marshal.ReadIntPtr(nativeData); var bytes = (byte*)nativeData; var nbBytes = 0; while (*(bytes + nbBytes) != 0) { nbBytes++; } - var stringData = StringEncoding.GetString(bytes, nbBytes); - if (gcHandlePtr != IntPtr.Zero) - { - var gcHandle = GCHandle.FromIntPtr(gcHandlePtr); - var stringBuilder = (StringBuilder)gcHandle.Target; - gcHandle.Free(); - stringBuilder.Append(stringData); - } - return stringData; + return StringEncoding.GetString(bytes, nbBytes); } } } diff --git a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs index bb77b61d..b1b99a75 100644 --- a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs +++ b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs @@ -30,13 +30,13 @@ internal static partial class LibPcapSafeNativeMethods [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] internal extern static int pcap_init( uint opts, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /* char* */ errbuf + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf ); [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] internal extern static int pcap_findalldevs( ref IntPtr /* pcap_if_t** */ alldevs, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /* char* */ errbuf + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf ); [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] @@ -44,7 +44,7 @@ internal extern static int pcap_findalldevs_ex( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] string /*char **/source, ref pcap_rmtauth /*pcap_rmtauth **/auth, ref IntPtr /*pcap_if_t ** */alldevs, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /*char * */errbuf + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /*char * */errbuf ); [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] @@ -57,19 +57,19 @@ internal extern static int pcap_findalldevs_ex( int flags, int read_timeout, ref pcap_rmtauth rmtauth, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder errbuf + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder errbuf ); [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] internal extern static PcapHandle /* pcap_t* */ pcap_create( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] string dev, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder errbuf + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder errbuf ); [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] internal extern static PcapHandle /* pcap_t* */ pcap_open_offline( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] string/*const char* */ fname, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder/* char* */ errbuf + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder/* char* */ errbuf ); [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] @@ -187,7 +187,7 @@ internal extern static int pcap_compile( internal extern static int pcap_setnonblock( PcapHandle /* pcap_if_t** */ adaptHandle, int nonblock, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /* char* */ errbuf + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf ); /// @@ -196,7 +196,7 @@ internal extern static int pcap_setnonblock( [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] internal extern static int pcap_getnonblock( PcapHandle /* pcap_if_t** */ adaptHandle, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /* char* */ errbuf + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf ); /// @@ -422,7 +422,7 @@ internal extern static int pcap_tstamp_type_name_to_val( internal extern static PcapHandle /* pcap_t* */ pcap_open_offline_with_tstamp_precision( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] string /* const char* */ fname, uint precision, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /* char* */ errbuf + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf ); /// @@ -488,7 +488,7 @@ internal extern static int pcap_tstamp_type_name_to_val( internal extern static IntPtr /* pcap_t* */ _pcap_hopen_offline_with_tstamp_precision( SafeHandle handle, uint precision, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /* char* */ errbuf + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf ); /// @@ -503,7 +503,7 @@ internal extern static int pcap_tstamp_type_name_to_val( internal extern static IntPtr /* pcap_t* */ _pcap_fopen_offline_with_tstamp_precision( SafeHandle fileObject, uint precision, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] StringBuilder /* char* */ errbuf + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf ); } } From 0464f053a39057b7e62382bba42004eb26193053 Mon Sep 17 00:00:00 2001 From: Ayoub Kaanich Date: Tue, 1 Oct 2024 23:06:01 +0200 Subject: [PATCH 3/6] Drop ICustomMarshaler for error string, use ErrorBuffer class instead.ss --- SharpPcap/LibPcap/CaptureFileReaderDevice.cs | 7 +- .../LibPcap/CaptureHandleReaderDevice.cs | 4 +- SharpPcap/LibPcap/LibPcapLiveDevice.cs | 18 ++-- .../LibPcapSafeNativeMethods.Encoding.cs | 82 +++++-------------- .../LibPcapSafeNativeMethods.Interop.cs | 22 ++--- SharpPcap/LibPcap/LibPcapSafeNativeMethods.cs | 6 +- SharpPcap/LibPcap/PcapInterface.cs | 13 ++- SharpPcap/Pcap.cs | 1 - SharpPcap/SharpPcap.csproj | 2 +- 9 files changed, 51 insertions(+), 104 deletions(-) diff --git a/SharpPcap/LibPcap/CaptureFileReaderDevice.cs b/SharpPcap/LibPcap/CaptureFileReaderDevice.cs index 1f6bfe3e..ab8bb0e2 100644 --- a/SharpPcap/LibPcap/CaptureFileReaderDevice.cs +++ b/SharpPcap/LibPcap/CaptureFileReaderDevice.cs @@ -72,8 +72,7 @@ public CaptureFileReaderDevice(string captureFilename) /// public override void Open(DeviceConfiguration configuration) { - // holds errors - StringBuilder errbuf = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE); //will hold errors + ErrorBuffer errbuf; //will hold errors PcapHandle adapterHandle; @@ -82,7 +81,7 @@ public override void Open(DeviceConfiguration configuration) var resolution = configuration.TimestampResolution ?? TimestampResolution.Microsecond; if (has_offline_with_tstamp_precision_support) { - adapterHandle = LibPcapSafeNativeMethods.pcap_open_offline_with_tstamp_precision(m_pcapFile, (uint)resolution, errbuf); + adapterHandle = LibPcapSafeNativeMethods.pcap_open_offline_with_tstamp_precision(m_pcapFile, (uint)resolution, out errbuf); } else { @@ -97,7 +96,7 @@ public override void Open(DeviceConfiguration configuration) ); } - adapterHandle = LibPcapSafeNativeMethods.pcap_open_offline(m_pcapFile, errbuf); + adapterHandle = LibPcapSafeNativeMethods.pcap_open_offline(m_pcapFile, out errbuf); } // handle error diff --git a/SharpPcap/LibPcap/CaptureHandleReaderDevice.cs b/SharpPcap/LibPcap/CaptureHandleReaderDevice.cs index 34993e72..115e07fe 100644 --- a/SharpPcap/LibPcap/CaptureHandleReaderDevice.cs +++ b/SharpPcap/LibPcap/CaptureHandleReaderDevice.cs @@ -48,14 +48,14 @@ public CaptureHandleReaderDevice(SafeHandle handle) public override void Open(DeviceConfiguration configuration) { // holds errors - StringBuilder errbuf = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE); + ErrorBuffer errbuf; var resolution = configuration.TimestampResolution ?? TimestampResolution.Microsecond; PcapHandle adapterHandle; try { adapterHandle = LibPcapSafeNativeMethods.pcap_open_handle_offline_with_tstamp_precision( - FileHandle, (uint)resolution, errbuf); + FileHandle, (uint)resolution, out errbuf); } catch (TypeLoadException ex) { diff --git a/SharpPcap/LibPcap/LibPcapLiveDevice.cs b/SharpPcap/LibPcap/LibPcapLiveDevice.cs index 2827dcd9..6e9dc65a 100644 --- a/SharpPcap/LibPcap/LibPcapLiveDevice.cs +++ b/SharpPcap/LibPcap/LibPcapLiveDevice.cs @@ -102,7 +102,7 @@ public override void Open(DeviceConfiguration configuration) // See https://www.tcpdump.org/manpages/pcap_set_immediate_mode.3pcap.html var mintocopy_supported = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - var errbuf = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE); //will hold errors + ErrorBuffer errbuf; //will hold errors // set the StopCaptureTimeout value to twice the read timeout to ensure that // we wait long enough before considering the capture thread to be stuck when stopping @@ -131,7 +131,7 @@ public override void Open(DeviceConfiguration configuration) { Handle = LibPcapSafeNativeMethods.pcap_create( Name, // name of the device - errbuf); // error buffer + out errbuf); // error buffer if (Handle.IsInvalid) { @@ -171,7 +171,7 @@ public override void Open(DeviceConfiguration configuration) (short)mode, // flags (short)configuration.ReadTimeout, // read timeout ref auth, // authentication - errbuf); // error buffer + out errbuf); // error buffer } catch (TypeLoadException) { @@ -275,14 +275,12 @@ public bool NonBlockingMode get { ThrowIfNotOpen("Can't get blocking mode, the device is closed"); - - var errbuf = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE); //will hold errors - int ret = LibPcapSafeNativeMethods.pcap_getnonblock(Handle, errbuf); + int ret = LibPcapSafeNativeMethods.pcap_getnonblock(Handle, out var errbuf); // Errorbuf is only filled when ret = -1 if (ret == -1) { - string err = "Unable to set get blocking" + errbuf.ToString(); + string err = "Unable to get blocking mode. " + errbuf.ToString(); throw new PcapException(err); } @@ -294,18 +292,16 @@ public bool NonBlockingMode { ThrowIfNotOpen("Can't set blocking mode, the device is closed"); - var errbuf = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE); //will hold errors - int block = disableBlocking; if (value) block = enableBlocking; - int ret = LibPcapSafeNativeMethods.pcap_setnonblock(Handle, block, errbuf); + int ret = LibPcapSafeNativeMethods.pcap_setnonblock(Handle, block, out var errbuf); // Errorbuf is only filled when ret = -1 if (ret == -1) { - string err = "Unable to set non blocking" + errbuf.ToString(); + string err = "Unable to set blocking mode. " + errbuf.ToString(); throw new PcapException(err); } } diff --git a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs index 98588a58..fcd3fa27 100644 --- a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs +++ b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs @@ -17,7 +17,7 @@ internal static partial class LibPcapSafeNativeMethods /// /// This defaul is good enough for .NET Framework and .NET Core on non Windows with Libpcap default config /// - private static readonly Encoding StringEncoding = Encoding.Default; + internal static readonly Encoding StringEncoding = Encoding.Default; private static Encoding ConfigureStringEncoding() { @@ -29,9 +29,8 @@ private static Encoding ConfigureStringEncoding() try { // Try to change Libpcap to UTF-8 mode - var errorBuffer = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE); const uint PCAP_CHAR_ENC_UTF_8 = 1; - var res = pcap_init(PCAP_CHAR_ENC_UTF_8, errorBuffer); + var res = pcap_init(PCAP_CHAR_ENC_UTF_8, out var _); if (res == 0) { // We made it @@ -48,66 +47,6 @@ private static Encoding ConfigureStringEncoding() return Encoding.GetEncoding(0); } - /// - /// Helper class to marshall StringBuilder depending on encoding used by Libpcap - /// - private class PcapStringBuilderMarshaler : ICustomMarshaler - { - - public static ICustomMarshaler GetInstance(string cookie) - { - return new PcapStringBuilderMarshaler(); - } - - public void CleanUpManagedData(object managedObj) - { - // Nothing to clean - } - - public void CleanUpNativeData(IntPtr nativeData) - { - // Nothing to clean - } - - public int GetNativeDataSize() - { - return -1; - } - - public IntPtr MarshalManagedToNative(object managedObj) - { - var builder = (StringBuilder)managedObj; - var byteCount = builder.Capacity + 1; - var gcHandle = GCHandle.ToIntPtr(GCHandle.Alloc(managedObj)); - - // The problem is that we need a reference to the StringBuilder in MarshalNativeToManaged - // So we get a pointer to it with GCHandle, and put it as prefix of the pointer we return - var ptr = Marshal.AllocHGlobal(byteCount + IntPtr.Size); - Marshal.WriteIntPtr(ptr, gcHandle); - ptr += IntPtr.Size; - return ptr; - } - - public unsafe object MarshalNativeToManaged(IntPtr nativeData) - { - var gcHandlePtr = Marshal.ReadIntPtr(nativeData - IntPtr.Size); - var bytes = (byte*)nativeData; - var nbBytes = 0; - while (*(bytes + nbBytes) != 0) - { - nbBytes++; - } - var stringData = StringEncoding.GetString(bytes, nbBytes); - - var gcHandle = GCHandle.FromIntPtr(gcHandlePtr); - var stringBuilder = (StringBuilder)gcHandle.Target; - gcHandle.Free(); - stringBuilder.Append(stringData); - - return null; - } - } - /// /// Helper class to marshall string depending on encoding used by Libpcap /// @@ -178,4 +117,21 @@ public unsafe object MarshalNativeToManaged(IntPtr nativeData) } } } + + [StructLayout(LayoutKind.Sequential)] + internal struct ErrorBuffer + { + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 256)] + internal byte[] Data; + + public override string ToString() + { + var nbBytes = 0; + while (Data[nbBytes] != 0) + { + nbBytes++; + } + return LibPcapSafeNativeMethods.StringEncoding.GetString(new Span(Data, 0, nbBytes)); + } + } } diff --git a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs index b1b99a75..d17e4eb9 100644 --- a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs +++ b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs @@ -30,13 +30,13 @@ internal static partial class LibPcapSafeNativeMethods [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] internal extern static int pcap_init( uint opts, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf + out ErrorBuffer /* char* */ errbuf ); [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] internal extern static int pcap_findalldevs( ref IntPtr /* pcap_if_t** */ alldevs, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf + out ErrorBuffer /* char* */ errbuf ); [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] @@ -44,7 +44,7 @@ internal extern static int pcap_findalldevs_ex( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] string /*char **/source, ref pcap_rmtauth /*pcap_rmtauth **/auth, ref IntPtr /*pcap_if_t ** */alldevs, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /*char * */errbuf + out ErrorBuffer /* char* */ errbuf ); [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] @@ -57,19 +57,19 @@ internal extern static int pcap_findalldevs_ex( int flags, int read_timeout, ref pcap_rmtauth rmtauth, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder errbuf + out ErrorBuffer /* char* */ errbuf ); [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] internal extern static PcapHandle /* pcap_t* */ pcap_create( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] string dev, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder errbuf + out ErrorBuffer /* char* */ errbuf ); [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] internal extern static PcapHandle /* pcap_t* */ pcap_open_offline( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] string/*const char* */ fname, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder/* char* */ errbuf + out ErrorBuffer /* char* */ errbuf ); [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] @@ -187,7 +187,7 @@ internal extern static int pcap_compile( internal extern static int pcap_setnonblock( PcapHandle /* pcap_if_t** */ adaptHandle, int nonblock, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf + out ErrorBuffer /* char* */ errbuf ); /// @@ -196,7 +196,7 @@ internal extern static int pcap_setnonblock( [DllImport(PCAP_DLL, CallingConvention = CallingConvention.Cdecl)] internal extern static int pcap_getnonblock( PcapHandle /* pcap_if_t** */ adaptHandle, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf + out ErrorBuffer /* char* */ errbuf ); /// @@ -422,7 +422,7 @@ internal extern static int pcap_tstamp_type_name_to_val( internal extern static PcapHandle /* pcap_t* */ pcap_open_offline_with_tstamp_precision( [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringMarshaler))] string /* const char* */ fname, uint precision, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf + out ErrorBuffer /* char* */ errbuf ); /// @@ -488,7 +488,7 @@ internal extern static int pcap_tstamp_type_name_to_val( internal extern static IntPtr /* pcap_t* */ _pcap_hopen_offline_with_tstamp_precision( SafeHandle handle, uint precision, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf + out ErrorBuffer /* char* */ errbuf ); /// @@ -503,7 +503,7 @@ internal extern static int pcap_tstamp_type_name_to_val( internal extern static IntPtr /* pcap_t* */ _pcap_fopen_offline_with_tstamp_precision( SafeHandle fileObject, uint precision, - [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(PcapStringBuilderMarshaler))] StringBuilder /* char* */ errbuf + out ErrorBuffer /* char* */ errbuf ); } } diff --git a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.cs b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.cs index c31fd2eb..177935be 100644 --- a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.cs +++ b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.cs @@ -93,11 +93,11 @@ internal static int pcap_get_tstamp_precision(PcapHandle /* pcap_t* p */ adapter /// Buffer that will receive an error description if an error occurs. /// internal static PcapHandle pcap_open_handle_offline_with_tstamp_precision( - SafeHandle handle, uint precision, StringBuilder errbuf) + SafeHandle handle, uint precision, out ErrorBuffer errbuf) { var pointer = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) - ? _pcap_hopen_offline_with_tstamp_precision(handle, precision, errbuf) - : _pcap_fopen_offline_with_tstamp_precision(handle, precision, errbuf); + ? _pcap_hopen_offline_with_tstamp_precision(handle, precision, out errbuf) + : _pcap_fopen_offline_with_tstamp_precision(handle, precision, out errbuf); if (pointer == IntPtr.Zero) { return PcapHandle.Invalid; diff --git a/SharpPcap/LibPcap/PcapInterface.cs b/SharpPcap/LibPcap/PcapInterface.cs index 6f289835..caa5dceb 100644 --- a/SharpPcap/LibPcap/PcapInterface.cs +++ b/SharpPcap/LibPcap/PcapInterface.cs @@ -176,15 +176,14 @@ static public IReadOnlyList GetAllPcapInterfaces(IPEndPoint sourc static public IReadOnlyList GetAllPcapInterfaces(string source, RemoteAuthentication credentials) { var devicePtr = IntPtr.Zero; - var errorBuffer = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE); var auth = RemoteAuthentication.CreateAuth(credentials); try { - var result = LibPcapSafeNativeMethods.pcap_findalldevs_ex(source, ref auth, ref devicePtr, errorBuffer); + var result = LibPcapSafeNativeMethods.pcap_findalldevs_ex(source, ref auth, ref devicePtr, out var errbuf); if (result < 0) { - throw new PcapException(errorBuffer.ToString()); + throw new PcapException(errbuf.ToString()); } } catch (TypeLoadException ex) @@ -206,12 +205,11 @@ static public IReadOnlyList GetAllPcapInterfaces(string source, R static public IReadOnlyList GetAllPcapInterfaces() { var devicePtr = IntPtr.Zero; - var errorBuffer = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE); - int result = LibPcapSafeNativeMethods.pcap_findalldevs(ref devicePtr, errorBuffer); + int result = LibPcapSafeNativeMethods.pcap_findalldevs(ref devicePtr, out var errbuf); if (result < 0) { - throw new PcapException(errorBuffer.ToString()); + throw new PcapException(errbuf.ToString()); } var pcapInterfaces = GetAllPcapInterfaces(devicePtr, null); @@ -260,8 +258,7 @@ public System.Collections.Generic.List TimestampsSupported { get { - StringBuilder errbuf = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE); //will hold errors - using (var handle = LibPcapSafeNativeMethods.pcap_create(Name, errbuf)) + using (var handle = LibPcapSafeNativeMethods.pcap_create(Name, out var errbuf)) { IntPtr typePtr = IntPtr.Zero; diff --git a/SharpPcap/Pcap.cs b/SharpPcap/Pcap.cs index 3c173bac..dfd7cc55 100644 --- a/SharpPcap/Pcap.cs +++ b/SharpPcap/Pcap.cs @@ -21,7 +21,6 @@ public class Pcap /* interface is loopback */ internal const uint PCAP_IF_LOOPBACK = 0x00000001; internal const int MAX_PACKET_SIZE = 65536; - internal const int PCAP_ERRBUF_SIZE = 256; // Constants for address families // These are set in a Pcap static initializer because the values diff --git a/SharpPcap/SharpPcap.csproj b/SharpPcap/SharpPcap.csproj index 5362aeca..ea31c580 100644 --- a/SharpPcap/SharpPcap.csproj +++ b/SharpPcap/SharpPcap.csproj @@ -7,7 +7,7 @@ SPDX-License-Identifier: MIT --> - netstandard2.0;net8.0 + net8.0 6.3.0 A packet capture framework for .NET Tamir Gal, Chris Morgan and others From 5df8f1d47987a4cb0ba86a4b2c4c326459953dd2 Mon Sep 17 00:00:00 2001 From: Ayoub Kaanich Date: Tue, 1 Oct 2024 23:11:08 +0200 Subject: [PATCH 4/6] Revert csproj changes --- SharpPcap/SharpPcap.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharpPcap/SharpPcap.csproj b/SharpPcap/SharpPcap.csproj index ea31c580..5362aeca 100644 --- a/SharpPcap/SharpPcap.csproj +++ b/SharpPcap/SharpPcap.csproj @@ -7,7 +7,7 @@ SPDX-License-Identifier: MIT --> - net8.0 + netstandard2.0;net8.0 6.3.0 A packet capture framework for .NET Tamir Gal, Chris Morgan and others From b2acced177e8976f06d0c83b9cd4f7d5e2f46eab Mon Sep 17 00:00:00 2001 From: Ayoub Kaanich Date: Tue, 1 Oct 2024 23:14:09 +0200 Subject: [PATCH 5/6] Fix build --- SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs index fcd3fa27..03c4f9ce 100644 --- a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs +++ b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs @@ -131,7 +131,7 @@ public override string ToString() { nbBytes++; } - return LibPcapSafeNativeMethods.StringEncoding.GetString(new Span(Data, 0, nbBytes)); + return LibPcapSafeNativeMethods.StringEncoding.GetString(Data, 0, nbBytes); } } } From 3b1b506fee6182acba35eb261324846b3a675560 Mon Sep 17 00:00:00 2001 From: Ayoub Kaanich Date: Mon, 7 Oct 2024 21:09:03 +0200 Subject: [PATCH 6/6] Cleanup --- SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs | 5 ++--- SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs | 3 --- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs index 03c4f9ce..18fa7805 100644 --- a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs +++ b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Encoding.cs @@ -15,7 +15,7 @@ internal static partial class LibPcapSafeNativeMethods { /// - /// This defaul is good enough for .NET Framework and .NET Core on non Windows with Libpcap default config + /// This default is good enough for .NET Framework and .NET Core on non Windows with Libpcap default config /// internal static readonly Encoding StringEncoding = Encoding.Default; @@ -30,7 +30,7 @@ private static Encoding ConfigureStringEncoding() { // Try to change Libpcap to UTF-8 mode const uint PCAP_CHAR_ENC_UTF_8 = 1; - var res = pcap_init(PCAP_CHAR_ENC_UTF_8, out var _); + var res = pcap_init(PCAP_CHAR_ENC_UTF_8, out _); if (res == 0) { // We made it @@ -106,7 +106,6 @@ public unsafe object MarshalNativeToManaged(IntPtr nativeData) { return null; } - var gcHandlePtr = Marshal.ReadIntPtr(nativeData); var bytes = (byte*)nativeData; var nbBytes = 0; while (*(bytes + nbBytes) != 0) diff --git a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs index d17e4eb9..3c6fe3ff 100644 --- a/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs +++ b/SharpPcap/LibPcap/LibPcapSafeNativeMethods.Interop.cs @@ -5,11 +5,8 @@ // SPDX-License-Identifier: MIT using System; -using System.IO; -using System.Reflection; using System.Runtime.InteropServices; using System.Security; -using System.Text; using static SharpPcap.LibPcap.PcapUnmanagedStructures; namespace SharpPcap.LibPcap