/// <summary> /// Open the device /// </summary> public override void Open(DeviceConfiguration configuration) { // set the device handle var has_open_dead_with_tstamp_precision_support = Pcap.LibpcapVersion >= new Version(1, 5, 1); var resolution = configuration.TimestampResolution ?? TimestampResolution.Microsecond; if (has_open_dead_with_tstamp_precision_support) { PcapHandle = LibPcapSafeNativeMethods.pcap_open_dead_with_tstamp_precision((int)configuration.LinkLayerType, configuration.Snaplen, (uint)resolution); } else { if (resolution != TimestampResolution.Microsecond) { configuration.RaiseConfigurationFailed( nameof(configuration.TimestampResolution), (int)PcapError.PlatformNotSupported, "pcap version is < 1.5.1, needs pcap_open_dead_with_tstamp_precision()" ); } PcapHandle = LibPcapSafeNativeMethods.pcap_open_dead((int)configuration.LinkLayerType, configuration.Snaplen); } m_pcapDumpHandle = LibPcapSafeNativeMethods.pcap_dump_open(PcapHandle, m_pcapFile); if (m_pcapDumpHandle == IntPtr.Zero) { throw new PcapException("Error opening dump file '" + LastError + "'"); } Active = true; }
/// <summary> /// Most pcap configuration functions have the signature int pcap_set_foo(pcap_t, int) /// This is a helper method to use them and detect/report errors /// </summary> /// <param name="configuration"></param> /// <param name="setter"></param> /// <param name="property"></param> /// <param name="value"></param> protected void Configure( DeviceConfiguration configuration, string property, Func <IntPtr, int, int> setter, int?value ) { if (value.HasValue) { var retval = setter(PcapHandle, value.Value); if (retval != 0) { configuration.RaiseConfigurationFailed(property, retval); } } }
/// <summary> /// Most pcap configuration functions have the signature int pcap_set_foo(pcap_t, int) /// those functions also set the error buffer, so we read it /// This is a helper method to use them and detect/report errors /// </summary> /// <param name="configuration"></param> /// <param name="setter"></param> /// <param name="property"></param> /// <param name="value"></param> protected void Configure( DeviceConfiguration configuration, string property, Func <PcapHandle, int, PcapError> setter, int?value ) { if (value.HasValue) { var retval = setter(Handle, value.Value); if (retval != 0) { configuration.RaiseConfigurationFailed(property, retval, GetLastError(Handle)); } } }
/// <summary> /// Open the device /// </summary> public override void Open(DeviceConfiguration configuration) { // holds errors StringBuilder errbuf = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE); //will hold errors PcapHandle adapterHandle; // Check if we need to open with a defined precision var has_offline_with_tstamp_precision_support = Pcap.LibpcapVersion >= new Version(1, 5, 1); var resolution = configuration.TimestampResolution ?? TimestampResolution.Microsecond; if (has_offline_with_tstamp_precision_support) { adapterHandle = LibPcapSafeNativeMethods.pcap_open_offline_with_tstamp_precision(m_pcapFile, (uint)resolution, errbuf); } else { // notify the user that they asked for a non-standard resolution but their libpcap // version lacks the necessary function if (resolution != TimestampResolution.Microsecond) { configuration.RaiseConfigurationFailed( nameof(configuration.TimestampResolution), (int)PcapError.PlatformNotSupported, "pcap version is < 1.5.1, needs pcap_open_offline_with_tstamp_precision()" ); } adapterHandle = LibPcapSafeNativeMethods.pcap_open_offline(m_pcapFile, errbuf); } // handle error if (adapterHandle.IsInvalid) { string err = "Unable to open offline adapter: " + errbuf.ToString(); throw new PcapException(err); } // set the device handle Handle = adapterHandle; base.Open(configuration); }
protected internal void ConfigureIfCompatible( bool compatible, DeviceConfiguration configuration, string property, Func <PcapHandle, int, PcapError> setter, int?value ) { if (!value.HasValue) { return; } if (!compatible) { configuration.RaiseConfigurationFailed( property, PcapError.Generic, $"Can not configure {property} with current device and selected modes" ); } else { Configure(configuration, property, setter, value); } }
/// <summary> /// Open the device. To start capturing call the 'StartCapture' function /// </summary> /// <param name="configuration"> /// A <see cref="DeviceConfiguration"/> /// </param> public override void Open(DeviceConfiguration configuration) { if (Opened) { return; } var credentials = configuration.Credentials ?? Interface.Credentials; var mode = configuration.Mode; // Check if immediate is supported var immediate_supported = Pcap.LibpcapVersion >= new Version(1, 5, 0); // Check if we can do immediate by setting mintocopy to 0 // 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 // set the StopCaptureTimeout value to twice the read timeout to ensure that // we wait long enough before considering the capture thread to be stuck when stopping // a background capture via StopCapture() // // NOTE: Doesn't affect Mono if unix poll is available, doesn't affect Linux because // Linux devices have no timeout, they always block. Only affects Windows devices. StopCaptureTimeout = new TimeSpan(0, 0, 0, 0, configuration.ReadTimeout * 2); // modes other than OpenFlags.Promiscuous require pcap_open() var otherModes = mode & ~DeviceModes.Promiscuous; if (immediate_supported || mintocopy_supported) { // We can do MaxResponsiveness through Immediate mode otherModes &= ~DeviceModes.MaxResponsiveness; } var immediateMode = configuration.Immediate; if (mode.HasFlag(DeviceModes.MaxResponsiveness)) { immediateMode = true; } // Some configurations can only be used with pcap_create var use_pcap_create = credentials == null && (short)otherModes == 0; if (use_pcap_create) { Handle = LibPcapSafeNativeMethods.pcap_create( Name, // name of the device errbuf); // error buffer // Those are configurations that pcap_open can handle differently Configure( configuration, nameof(configuration.Snaplen), LibPcapSafeNativeMethods.pcap_set_snaplen, configuration.Snaplen ); Configure( configuration, "Promiscuous", LibPcapSafeNativeMethods.pcap_set_promisc, (int)(mode & DeviceModes.Promiscuous) ); Configure( configuration, nameof(configuration.ReadTimeout), LibPcapSafeNativeMethods.pcap_set_timeout, configuration.ReadTimeout ); } else { // We got authentication, so this is an rpcap device var auth = RemoteAuthentication.CreateAuth(credentials); // Immediate and MaxResponsiveness are the same thing if (immediateMode == true) { mode |= DeviceModes.MaxResponsiveness; } // No need to worry about it anymore immediateMode = null; try { Handle = LibPcapSafeNativeMethods.pcap_open( Name, // name of the device configuration.Snaplen, // portion of the packet to capture. (short)mode, // flags (short)configuration.ReadTimeout, // read timeout ref auth, // authentication errbuf); // error buffer } catch (TypeLoadException) { var reason = credentials != null ? "Remote PCAP" : "Requested DeviceModes"; var err = $"Unable to open the adapter '{Name}'. {reason} not supported"; throw new PcapException(err, PcapError.PlatformNotSupported); } } if (Handle.IsInvalid) { var err = $"Unable to open the adapter '{Name}'. {errbuf}"; throw new PcapException(err); } ConfigureIfCompatible(use_pcap_create, configuration, nameof(configuration.TimestampResolution), LibPcapSafeNativeMethods.pcap_set_tstamp_precision, (int?)configuration.TimestampResolution ); ConfigureIfCompatible(use_pcap_create, configuration, nameof(configuration.TimestampType), LibPcapSafeNativeMethods.pcap_set_tstamp_type, (int?)configuration.TimestampType ); ConfigureIfCompatible(use_pcap_create, configuration, nameof(configuration.Monitor), LibPcapSafeNativeMethods.pcap_set_rfmon, (int?)configuration.Monitor ); ConfigureIfCompatible(use_pcap_create, configuration, nameof(configuration.BufferSize), LibPcapSafeNativeMethods.pcap_set_buffer_size, configuration.BufferSize ); if (immediateMode.HasValue) { if (!immediate_supported && !mintocopy_supported) { configuration.RaiseConfigurationFailed( nameof(configuration.Immediate), PcapError.PlatformNotSupported, "Immediate mode not available" ); } else if (immediate_supported) { var immediate = immediateMode.Value ? 1 : 0; Configure( configuration, nameof(configuration.Immediate), LibPcapSafeNativeMethods.pcap_set_immediate_mode, immediate ); } } // pcap_open returns an already activated device if (use_pcap_create) { var activationResult = LibPcapSafeNativeMethods.pcap_activate(Handle); if (activationResult < 0) { string err = "Unable to activate the adapter (" + Name + ")."; throw new PcapException(err, activationResult); } } base.Open(configuration); // retrieve the file descriptor of the adapter for use with poll() if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { FileDescriptor = LibPcapSafeNativeMethods.pcap_get_selectable_fd(Handle); } // Below configurations must be done after the device gets activated Configure( configuration, nameof(configuration.KernelBufferSize), LibPcapSafeNativeMethods.pcap_setbuff, configuration.KernelBufferSize ); if (immediateMode == true && mintocopy_supported && !immediate_supported) { Configure( configuration, nameof(configuration.Immediate), LibPcapSafeNativeMethods.pcap_setmintocopy, 0 ); } Configure( configuration, nameof(configuration.MinToCopy), LibPcapSafeNativeMethods.pcap_setmintocopy, configuration.MinToCopy ); }
/// <summary> /// Open the device. To start capturing call the 'StartCapture' function /// </summary> /// <param name="configuration"> /// A <see cref="DeviceConfiguration"/> /// </param> public override void Open(DeviceConfiguration configuration) { var credentials = configuration.Credentials ?? Interface.Credentials; var mode = configuration.Mode; if (!Opened) { StringBuilder errbuf = new StringBuilder(Pcap.PCAP_ERRBUF_SIZE); //will hold errors // set the StopCaptureTimeout value to twice the read timeout to ensure that // we wait long enough before considering the capture thread to be stuck when stopping // a background capture via StopCapture() // // NOTE: Doesn't affect Mono if unix poll is available, doesn't affect Linux because // Linux devices have no timeout, they always block. Only affects Windows devices. StopCaptureTimeout = new TimeSpan(0, 0, 0, 0, configuration.ReadTimeout * 2); // modes other than OpenFlags.Promiscuous require pcap_open() var otherModes = mode & ~DeviceModes.Promiscuous; if ((credentials == null) || ((short)otherModes != 0) || (configuration.TimestampResolution != null)) { PcapHandle = LibPcapSafeNativeMethods.pcap_create( Name, // name of the device errbuf); // error buffer Configure( configuration, nameof(configuration.Snaplen), LibPcapSafeNativeMethods.pcap_set_snaplen, configuration.Snaplen ); Configure( configuration, "Promiscuous", LibPcapSafeNativeMethods.pcap_set_promisc, (int)(mode & DeviceModes.Promiscuous) ); Configure( configuration, nameof(configuration.ReadTimeout), LibPcapSafeNativeMethods.pcap_set_timeout, configuration.ReadTimeout ); if (configuration.TimestampResolution.HasValue) { Configure( configuration, nameof(configuration.TimestampResolution), LibPcapSafeNativeMethods.pcap_set_tstamp_precision, (int)configuration.TimestampResolution ); } if (configuration.TimestampType.HasValue) { Configure( configuration, nameof(configuration.TimestampType), LibPcapSafeNativeMethods.pcap_set_tstamp_type, (int)configuration.TimestampType ); } } else { // We got authentication, so this is an rpcap device var auth = RemoteAuthentication.CreateAuth(credentials); PcapHandle = LibPcapSafeNativeMethods.pcap_open( Name, // name of the device configuration.Snaplen, // portion of the packet to capture. (short)mode, // flags (short)configuration.ReadTimeout, // read timeout ref auth, // authentication errbuf); // error buffer } if (PcapHandle == IntPtr.Zero) { string err = "Unable to open the adapter (" + Name + "). " + errbuf.ToString(); throw new PcapException(err); } Configure( configuration, nameof(configuration.Monitor), LibPcapSafeNativeMethods.pcap_set_rfmon, (int?)configuration.Monitor ); Configure( configuration, nameof(configuration.BufferSize), LibPcapSafeNativeMethods.pcap_set_buffer_size, configuration.BufferSize ); // Check if immediate is supported var immediate_supported = Pcap.LibpcapVersion >= new Version(1, 5, 0); // Check if we can do immediate by setting mintocopy to 0 // See https://www.tcpdump.org/manpages/pcap_set_immediate_mode.3pcap.html var mintocopy_supported = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); if (configuration.Immediate.HasValue) { if (!immediate_supported && !mintocopy_supported) { configuration.RaiseConfigurationFailed( nameof(configuration.Immediate), (int)PcapError.PlatformNotSupported ); } else if (immediate_supported) { var immediate = configuration.Immediate.Value ? 1 : 0; Configure( configuration, nameof(configuration.Immediate), LibPcapSafeNativeMethods.pcap_set_immediate_mode, immediate ); } } var activationResult = LibPcapSafeNativeMethods.pcap_activate(PcapHandle); if (activationResult < 0) { string err = "Unable to activate the adapter (" + Name + "). Return code: " + activationResult.ToString(); throw new PcapException(err); } Active = true; // retrieve the file descriptor of the adapter for use with poll() if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { FileDescriptor = LibPcapSafeNativeMethods.pcap_get_selectable_fd(PcapHandle); } // Below configurations must be done after the device gets activated Configure( configuration, nameof(configuration.KernelBufferSize), LibPcapSafeNativeMethods.pcap_setbuff, configuration.KernelBufferSize ); if (configuration.Immediate == true && mintocopy_supported && !immediate_supported) { Configure( configuration, nameof(configuration.Immediate), LibPcapSafeNativeMethods.pcap_setmintocopy, 0 ); } Configure( configuration, nameof(configuration.MinToCopy), LibPcapSafeNativeMethods.pcap_setmintocopy, configuration.MinToCopy ); } }