Smdn.Net.AddressResolution version 1.0.0-preview5
Pre-release
Pre-release
·
186 commits
to main
since this release
Released package
Release notes
The full release notes are available at gist.
Change log
Change log in this release:
- 2023-03-23 update assembly version
- 2023-03-23 bump Smdn.MSBuild.ProjectAssets.Library up to 1.4.7
- 2023-03-23 improve informational logs
- 2023-03-23 fix naming
- 2023-03-23 rename file
- 2023-03-23 add resolver implementation using 'arp-scan' command
- 2023-03-23 define the maximum number of parallel ARP scannings
- 2023-03-23 log the process exit code
- 2023-03-23 suppress warning SA1305
- 2023-03-23 change API to mark addresses as invalid with TAddress instead of TResolvedAddress
- 2023-03-23 add support for specifying '-e <iface>' for nmap options
API changes
API changes in this release:
diff --git a/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-net6.0.apilist.cs b/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-net6.0.apilist.cs
index 8de9632..235f0f0 100644
--- a/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-net6.0.apilist.cs
+++ b/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-net6.0.apilist.cs
@@ -1,88 +1,92 @@
-// Smdn.Net.AddressResolution.dll (Smdn.Net.AddressResolution-1.0.0-preview4)
+// Smdn.Net.AddressResolution.dll (Smdn.Net.AddressResolution-1.0.0-preview5)
// Name: Smdn.Net.AddressResolution
// AssemblyVersion: 1.0.0.0
-// InformationalVersion: 1.0.0-preview4+f17248a683dc95a5f8a1d3f3ec79fb49b8b2852f
+// InformationalVersion: 1.0.0-preview5+fe261fa7dd16c43347c28935b3055ec3b8ab0674
// TargetFramework: .NETCoreApp,Version=v6.0
// Configuration: Release
// Referenced assemblies:
// Microsoft.Extensions.DependencyInjection.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// System.Collections.Concurrent, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.ComponentModel, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Diagnostics.Process, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Linq, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Memory, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
// System.Net.NetworkInformation, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Net.Primitives, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Runtime, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
// System.Runtime.InteropServices.RuntimeInformation, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Threading, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
#nullable enable annotations
using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Smdn.Net.AddressResolution;
namespace Smdn.Net {
public static class PhysicalAddressExtensions {
public static string ToMacAddressString(this PhysicalAddress hardwareAddress, char delimiter = ':') {}
}
}
namespace Smdn.Net.AddressResolution {
public interface IAddressResolver<TAddress, TResolvedAddress> {
- void Invalidate(TResolvedAddress resolvedAddress);
+ void Invalidate(TAddress address);
ValueTask<TResolvedAddress> ResolveAsync(TAddress address, CancellationToken cancellationToken);
}
public abstract class MacAddressResolver :
IAddressResolver<IPAddress, PhysicalAddress>,
IAddressResolver<PhysicalAddress, IPAddress>,
IDisposable
{
protected static readonly PhysicalAddress AllZeroMacAddress; // = "000000000000"
public static MacAddressResolver Null { get; }
public static MacAddressResolver Create(MacAddressResolverOptions? options = null, IServiceProvider? serviceProvider = null) {}
protected MacAddressResolver(ILogger? logger = null) {}
public abstract bool HasInvalidated { get; }
protected ILogger? Logger { get; }
protected virtual void Dispose(bool disposing) {}
public void Dispose() {}
- public void Invalidate(IPAddress resolvedIPAddress) {}
- public void Invalidate(PhysicalAddress resolvedMacAddress) {}
- protected abstract void InvalidateCore(IPAddress resolvedIPAddress);
- protected abstract void InvalidateCore(PhysicalAddress resolvedMacAddress);
+ public void Invalidate(IPAddress ipAddress) {}
+ public void Invalidate(PhysicalAddress macAddress) {}
+ protected abstract void InvalidateCore(IPAddress ipAddress);
+ protected abstract void InvalidateCore(PhysicalAddress macAddress);
public ValueTask RefreshCacheAsync(CancellationToken cancellationToken = default) {}
protected virtual ValueTask RefreshCacheAsyncCore(CancellationToken cancellationToken) {}
public ValueTask RefreshInvalidatedCacheAsync(CancellationToken cancellationToken = default) {}
protected virtual ValueTask RefreshInvalidatedCacheAsyncCore(CancellationToken cancellationToken) {}
public ValueTask<PhysicalAddress?> ResolveIPAddressToMacAddressAsync(IPAddress ipAddress, CancellationToken cancellationToken = default) {}
protected abstract ValueTask<PhysicalAddress?> ResolveIPAddressToMacAddressAsyncCore(IPAddress ipAddress, CancellationToken cancellationToken);
public ValueTask<IPAddress?> ResolveMacAddressToIPAddressAsync(PhysicalAddress macAddress, CancellationToken cancellationToken = default) {}
protected abstract ValueTask<IPAddress?> ResolveMacAddressToIPAddressAsyncCore(PhysicalAddress macAddress, CancellationToken cancellationToken);
- void IAddressResolver<IPAddress, PhysicalAddress>.Invalidate(PhysicalAddress resolvedAddress) {}
+ void IAddressResolver<IPAddress, PhysicalAddress>.Invalidate(IPAddress address) {}
ValueTask<PhysicalAddress?> IAddressResolver<IPAddress, PhysicalAddress>.ResolveAsync(IPAddress address, CancellationToken cancellationToken) {}
- void IAddressResolver<PhysicalAddress, IPAddress>.Invalidate(IPAddress resolvedAddress) {}
+ void IAddressResolver<PhysicalAddress, IPAddress>.Invalidate(PhysicalAddress address) {}
ValueTask<IPAddress?> IAddressResolver<PhysicalAddress, IPAddress>.ResolveAsync(PhysicalAddress address, CancellationToken cancellationToken) {}
protected void ThrowIfDisposed() {}
}
public sealed class MacAddressResolverOptions {
public static readonly MacAddressResolverOptions Default; // = "Smdn.Net.AddressResolution.MacAddressResolverOptions"
public MacAddressResolverOptions() {}
- public string? NmapTargetSpecification { get; init; }
+ public string? ArpScanCommandInterfaceSpecification { get; init; }
+ public string? ArpScanCommandTargetSpecification { get; init; }
+ public string? NmapCommandInterfaceSpecification { get; init; }
+ public string? NmapCommandTargetSpecification { get; init; }
public TimeSpan ProcfsArpFullScanInterval { get; init; }
}
}
// API list generated by Smdn.Reflection.ReverseGenerating.ListApi.MSBuild.Tasks v1.2.1.0.
// Smdn.Reflection.ReverseGenerating.ListApi.Core v1.2.0.0 (https://github.com/smdn/Smdn.Reflection.ReverseGenerating)
diff --git a/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-net7.0.apilist.cs b/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-net7.0.apilist.cs
new file mode 100644
index 0000000..d9d912b
--- /dev/null
+++ b/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-net7.0.apilist.cs
@@ -0,0 +1,91 @@
+// Smdn.Net.AddressResolution.dll (Smdn.Net.AddressResolution-1.0.0-preview5)
+// Name: Smdn.Net.AddressResolution
+// AssemblyVersion: 1.0.0.0
+// InformationalVersion: 1.0.0-preview5+fe261fa7dd16c43347c28935b3055ec3b8ab0674
+// TargetFramework: .NETCoreApp,Version=v7.0
+// Configuration: Release
+// Referenced assemblies:
+// Microsoft.Extensions.DependencyInjection.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
+// Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
+// System.Collections.Concurrent, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.ComponentModel, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Diagnostics.Process, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Linq, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Memory, Version=7.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
+// System.Net.NetworkInformation, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Net.Primitives, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Runtime, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+// System.Threading, Version=7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a
+#nullable enable annotations
+
+using System;
+using System.Net;
+using System.Net.NetworkInformation;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+using Smdn.Net.AddressResolution;
+
+namespace Smdn.Net {
+ public static class PhysicalAddressExtensions {
+ public static string ToMacAddressString(this PhysicalAddress hardwareAddress, char delimiter = ':') {}
+ }
+}
+
+namespace Smdn.Net.AddressResolution {
+ public interface IAddressResolver<TAddress, TResolvedAddress> {
+ void Invalidate(TAddress address);
+ ValueTask<TResolvedAddress> ResolveAsync(TAddress address, CancellationToken cancellationToken);
+ }
+
+ public abstract class MacAddressResolver :
+ IAddressResolver<IPAddress, PhysicalAddress>,
+ IAddressResolver<PhysicalAddress, IPAddress>,
+ IDisposable
+ {
+ protected static readonly PhysicalAddress AllZeroMacAddress; // = "000000000000"
+
+ public static MacAddressResolver Null { get; }
+
+ public static MacAddressResolver Create(MacAddressResolverOptions? options = null, IServiceProvider? serviceProvider = null) {}
+
+ protected MacAddressResolver(ILogger? logger = null) {}
+
+ public abstract bool HasInvalidated { get; }
+ protected ILogger? Logger { get; }
+
+ protected virtual void Dispose(bool disposing) {}
+ public void Dispose() {}
+ public void Invalidate(IPAddress ipAddress) {}
+ public void Invalidate(PhysicalAddress macAddress) {}
+ protected abstract void InvalidateCore(IPAddress ipAddress);
+ protected abstract void InvalidateCore(PhysicalAddress macAddress);
+ public ValueTask RefreshCacheAsync(CancellationToken cancellationToken = default) {}
+ protected virtual ValueTask RefreshCacheAsyncCore(CancellationToken cancellationToken) {}
+ public ValueTask RefreshInvalidatedCacheAsync(CancellationToken cancellationToken = default) {}
+ protected virtual ValueTask RefreshInvalidatedCacheAsyncCore(CancellationToken cancellationToken) {}
+ public ValueTask<PhysicalAddress?> ResolveIPAddressToMacAddressAsync(IPAddress ipAddress, CancellationToken cancellationToken = default) {}
+ protected abstract ValueTask<PhysicalAddress?> ResolveIPAddressToMacAddressAsyncCore(IPAddress ipAddress, CancellationToken cancellationToken);
+ public ValueTask<IPAddress?> ResolveMacAddressToIPAddressAsync(PhysicalAddress macAddress, CancellationToken cancellationToken = default) {}
+ protected abstract ValueTask<IPAddress?> ResolveMacAddressToIPAddressAsyncCore(PhysicalAddress macAddress, CancellationToken cancellationToken);
+ void IAddressResolver<IPAddress, PhysicalAddress>.Invalidate(IPAddress address) {}
+ ValueTask<PhysicalAddress?> IAddressResolver<IPAddress, PhysicalAddress>.ResolveAsync(IPAddress address, CancellationToken cancellationToken) {}
+ void IAddressResolver<PhysicalAddress, IPAddress>.Invalidate(PhysicalAddress address) {}
+ ValueTask<IPAddress?> IAddressResolver<PhysicalAddress, IPAddress>.ResolveAsync(PhysicalAddress address, CancellationToken cancellationToken) {}
+ protected void ThrowIfDisposed() {}
+ }
+
+ public sealed class MacAddressResolverOptions {
+ public static readonly MacAddressResolverOptions Default; // = "Smdn.Net.AddressResolution.MacAddressResolverOptions"
+
+ public MacAddressResolverOptions() {}
+
+ public string? ArpScanCommandInterfaceSpecification { get; init; }
+ public string? ArpScanCommandTargetSpecification { get; init; }
+ public string? NmapCommandInterfaceSpecification { get; init; }
+ public string? NmapCommandTargetSpecification { get; init; }
+ public TimeSpan ProcfsArpFullScanInterval { get; init; }
+ }
+}
+// API list generated by Smdn.Reflection.ReverseGenerating.ListApi.MSBuild.Tasks v1.2.1.0.
+// Smdn.Reflection.ReverseGenerating.ListApi.Core v1.2.0.0 (https://github.com/smdn/Smdn.Reflection.ReverseGenerating)
diff --git a/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-netstandard2.0.apilist.cs b/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-netstandard2.0.apilist.cs
index f9d6a20..f2a6c75 100644
--- a/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-netstandard2.0.apilist.cs
+++ b/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-netstandard2.0.apilist.cs
@@ -1,82 +1,85 @@
-// Smdn.Net.AddressResolution.dll (Smdn.Net.AddressResolution-1.0.0-preview4)
+// Smdn.Net.AddressResolution.dll (Smdn.Net.AddressResolution-1.0.0-preview5)
// Name: Smdn.Net.AddressResolution
// AssemblyVersion: 1.0.0.0
-// InformationalVersion: 1.0.0-preview4+f17248a683dc95a5f8a1d3f3ec79fb49b8b2852f
+// InformationalVersion: 1.0.0-preview5+fe261fa7dd16c43347c28935b3055ec3b8ab0674
// TargetFramework: .NETStandard,Version=v2.0
// Configuration: Release
// Referenced assemblies:
// Microsoft.Bcl.AsyncInterfaces, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
// Microsoft.Extensions.DependencyInjection.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
// netstandard, Version=2.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
#nullable enable annotations
using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Smdn.Net.AddressResolution;
namespace Smdn.Net {
public static class PhysicalAddressExtensions {
public static string ToMacAddressString(this PhysicalAddress hardwareAddress, char delimiter = ':') {}
}
}
namespace Smdn.Net.AddressResolution {
public interface IAddressResolver<TAddress, TResolvedAddress> {
- void Invalidate(TResolvedAddress resolvedAddress);
+ void Invalidate(TAddress address);
ValueTask<TResolvedAddress> ResolveAsync(TAddress address, CancellationToken cancellationToken);
}
public abstract class MacAddressResolver :
IAddressResolver<IPAddress, PhysicalAddress>,
IAddressResolver<PhysicalAddress, IPAddress>,
IDisposable
{
protected static readonly PhysicalAddress AllZeroMacAddress; // = "000000000000"
public static MacAddressResolver Null { get; }
public static MacAddressResolver Create(MacAddressResolverOptions? options = null, IServiceProvider? serviceProvider = null) {}
protected MacAddressResolver(ILogger? logger = null) {}
public abstract bool HasInvalidated { get; }
protected ILogger? Logger { get; }
protected virtual void Dispose(bool disposing) {}
public void Dispose() {}
- public void Invalidate(IPAddress resolvedIPAddress) {}
- public void Invalidate(PhysicalAddress resolvedMacAddress) {}
- protected abstract void InvalidateCore(IPAddress resolvedIPAddress);
- protected abstract void InvalidateCore(PhysicalAddress resolvedMacAddress);
+ public void Invalidate(IPAddress ipAddress) {}
+ public void Invalidate(PhysicalAddress macAddress) {}
+ protected abstract void InvalidateCore(IPAddress ipAddress);
+ protected abstract void InvalidateCore(PhysicalAddress macAddress);
public ValueTask RefreshCacheAsync(CancellationToken cancellationToken = default) {}
protected virtual ValueTask RefreshCacheAsyncCore(CancellationToken cancellationToken) {}
public ValueTask RefreshInvalidatedCacheAsync(CancellationToken cancellationToken = default) {}
protected virtual ValueTask RefreshInvalidatedCacheAsyncCore(CancellationToken cancellationToken) {}
public ValueTask<PhysicalAddress?> ResolveIPAddressToMacAddressAsync(IPAddress ipAddress, CancellationToken cancellationToken = default) {}
protected abstract ValueTask<PhysicalAddress?> ResolveIPAddressToMacAddressAsyncCore(IPAddress ipAddress, CancellationToken cancellationToken);
public ValueTask<IPAddress?> ResolveMacAddressToIPAddressAsync(PhysicalAddress macAddress, CancellationToken cancellationToken = default) {}
protected abstract ValueTask<IPAddress?> ResolveMacAddressToIPAddressAsyncCore(PhysicalAddress macAddress, CancellationToken cancellationToken);
- void IAddressResolver<IPAddress, PhysicalAddress>.Invalidate(PhysicalAddress resolvedAddress) {}
+ void IAddressResolver<IPAddress, PhysicalAddress>.Invalidate(IPAddress address) {}
ValueTask<PhysicalAddress?> IAddressResolver<IPAddress, PhysicalAddress>.ResolveAsync(IPAddress address, CancellationToken cancellationToken) {}
- void IAddressResolver<PhysicalAddress, IPAddress>.Invalidate(IPAddress resolvedAddress) {}
+ void IAddressResolver<PhysicalAddress, IPAddress>.Invalidate(PhysicalAddress address) {}
ValueTask<IPAddress?> IAddressResolver<PhysicalAddress, IPAddress>.ResolveAsync(PhysicalAddress address, CancellationToken cancellationToken) {}
protected void ThrowIfDisposed() {}
}
public sealed class MacAddressResolverOptions {
public static readonly MacAddressResolverOptions Default; // = "Smdn.Net.AddressResolution.MacAddressResolverOptions"
public MacAddressResolverOptions() {}
- public string? NmapTargetSpecification { get; init; }
+ public string? ArpScanCommandInterfaceSpecification { get; init; }
+ public string? ArpScanCommandTargetSpecification { get; init; }
+ public string? NmapCommandInterfaceSpecification { get; init; }
+ public string? NmapCommandTargetSpecification { get; init; }
public TimeSpan ProcfsArpFullScanInterval { get; init; }
}
}
// API list generated by Smdn.Reflection.ReverseGenerating.ListApi.MSBuild.Tasks v1.2.1.0.
// Smdn.Reflection.ReverseGenerating.ListApi.Core v1.2.0.0 (https://github.com/smdn/Smdn.Reflection.ReverseGenerating)
diff --git a/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-netstandard2.1.apilist.cs b/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-netstandard2.1.apilist.cs
index 565bdda..bb31c94 100644
--- a/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-netstandard2.1.apilist.cs
+++ b/doc/api-list/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution-netstandard2.1.apilist.cs
@@ -1,80 +1,83 @@
-// Smdn.Net.AddressResolution.dll (Smdn.Net.AddressResolution-1.0.0-preview4)
+// Smdn.Net.AddressResolution.dll (Smdn.Net.AddressResolution-1.0.0-preview5)
// Name: Smdn.Net.AddressResolution
// AssemblyVersion: 1.0.0.0
-// InformationalVersion: 1.0.0-preview4+f17248a683dc95a5f8a1d3f3ec79fb49b8b2852f
+// InformationalVersion: 1.0.0-preview5+fe261fa7dd16c43347c28935b3055ec3b8ab0674
// TargetFramework: .NETStandard,Version=v2.1
// Configuration: Release
// Referenced assemblies:
// Microsoft.Extensions.DependencyInjection.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// Microsoft.Extensions.Logging.Abstractions, Version=6.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60
// netstandard, Version=2.1.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51
#nullable enable annotations
using System;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
using Smdn.Net.AddressResolution;
namespace Smdn.Net {
public static class PhysicalAddressExtensions {
public static string ToMacAddressString(this PhysicalAddress hardwareAddress, char delimiter = ':') {}
}
}
namespace Smdn.Net.AddressResolution {
public interface IAddressResolver<TAddress, TResolvedAddress> {
- void Invalidate(TResolvedAddress resolvedAddress);
+ void Invalidate(TAddress address);
ValueTask<TResolvedAddress> ResolveAsync(TAddress address, CancellationToken cancellationToken);
}
public abstract class MacAddressResolver :
IAddressResolver<IPAddress, PhysicalAddress>,
IAddressResolver<PhysicalAddress, IPAddress>,
IDisposable
{
protected static readonly PhysicalAddress AllZeroMacAddress; // = "000000000000"
public static MacAddressResolver Null { get; }
public static MacAddressResolver Create(MacAddressResolverOptions? options = null, IServiceProvider? serviceProvider = null) {}
protected MacAddressResolver(ILogger? logger = null) {}
public abstract bool HasInvalidated { get; }
protected ILogger? Logger { get; }
protected virtual void Dispose(bool disposing) {}
public void Dispose() {}
- public void Invalidate(IPAddress resolvedIPAddress) {}
- public void Invalidate(PhysicalAddress resolvedMacAddress) {}
- protected abstract void InvalidateCore(IPAddress resolvedIPAddress);
- protected abstract void InvalidateCore(PhysicalAddress resolvedMacAddress);
+ public void Invalidate(IPAddress ipAddress) {}
+ public void Invalidate(PhysicalAddress macAddress) {}
+ protected abstract void InvalidateCore(IPAddress ipAddress);
+ protected abstract void InvalidateCore(PhysicalAddress macAddress);
public ValueTask RefreshCacheAsync(CancellationToken cancellationToken = default) {}
protected virtual ValueTask RefreshCacheAsyncCore(CancellationToken cancellationToken) {}
public ValueTask RefreshInvalidatedCacheAsync(CancellationToken cancellationToken = default) {}
protected virtual ValueTask RefreshInvalidatedCacheAsyncCore(CancellationToken cancellationToken) {}
public ValueTask<PhysicalAddress?> ResolveIPAddressToMacAddressAsync(IPAddress ipAddress, CancellationToken cancellationToken = default) {}
protected abstract ValueTask<PhysicalAddress?> ResolveIPAddressToMacAddressAsyncCore(IPAddress ipAddress, CancellationToken cancellationToken);
public ValueTask<IPAddress?> ResolveMacAddressToIPAddressAsync(PhysicalAddress macAddress, CancellationToken cancellationToken = default) {}
protected abstract ValueTask<IPAddress?> ResolveMacAddressToIPAddressAsyncCore(PhysicalAddress macAddress, CancellationToken cancellationToken);
- void IAddressResolver<IPAddress, PhysicalAddress>.Invalidate(PhysicalAddress resolvedAddress) {}
+ void IAddressResolver<IPAddress, PhysicalAddress>.Invalidate(IPAddress address) {}
ValueTask<PhysicalAddress?> IAddressResolver<IPAddress, PhysicalAddress>.ResolveAsync(IPAddress address, CancellationToken cancellationToken) {}
- void IAddressResolver<PhysicalAddress, IPAddress>.Invalidate(IPAddress resolvedAddress) {}
+ void IAddressResolver<PhysicalAddress, IPAddress>.Invalidate(PhysicalAddress address) {}
ValueTask<IPAddress?> IAddressResolver<PhysicalAddress, IPAddress>.ResolveAsync(PhysicalAddress address, CancellationToken cancellationToken) {}
protected void ThrowIfDisposed() {}
}
public sealed class MacAddressResolverOptions {
public static readonly MacAddressResolverOptions Default; // = "Smdn.Net.AddressResolution.MacAddressResolverOptions"
public MacAddressResolverOptions() {}
- public string? NmapTargetSpecification { get; init; }
+ public string? ArpScanCommandInterfaceSpecification { get; init; }
+ public string? ArpScanCommandTargetSpecification { get; init; }
+ public string? NmapCommandInterfaceSpecification { get; init; }
+ public string? NmapCommandTargetSpecification { get; init; }
public TimeSpan ProcfsArpFullScanInterval { get; init; }
}
}
// API list generated by Smdn.Reflection.ReverseGenerating.ListApi.MSBuild.Tasks v1.2.1.0.
// Smdn.Reflection.ReverseGenerating.ListApi.Core v1.2.0.0 (https://github.com/smdn/Smdn.Reflection.ReverseGenerating)
Full changes
Full changes in this release:
diff --git a/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.Arp/ProcfsArpMacAddressResolver.cs b/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.Arp/ProcfsArpMacAddressResolver.cs
index 5693ea8..7026981 100644
--- a/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.Arp/ProcfsArpMacAddressResolver.cs
+++ b/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.Arp/ProcfsArpMacAddressResolver.cs
@@ -3,7 +3,9 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
+using System.Diagnostics;
using System.IO;
+using System.Linq;
using System.Net;
using System.Net.NetworkInformation;
using System.Threading;
@@ -15,6 +17,7 @@ namespace Smdn.Net.AddressResolution.Arp;
internal partial class ProcfsArpMacAddressResolver : MacAddressResolver {
private const string PathToProcNetArp = "/proc/net/arp";
+ private const int ArpScanParallelMax = 3;
public static bool IsSupported => File.Exists(PathToProcNetArp);
@@ -23,10 +26,17 @@ internal partial class ProcfsArpMacAddressResolver : MacAddressResolver {
IServiceProvider? serviceProvider
)
{
- if (ProcfsArpNmapScanMacAddressResolver.IsSupported) {
- return new ProcfsArpNmapScanMacAddressResolver(
+ if (ProcfsArpWithArpScanCommandMacAddressResolver.IsSupported) {
+ return new ProcfsArpWithArpScanCommandMacAddressResolver(
options: options,
- logger: serviceProvider?.GetService<ILoggerFactory>()?.CreateLogger<ProcfsArpNmapScanMacAddressResolver>()
+ logger: serviceProvider?.GetService<ILoggerFactory>()?.CreateLogger<ProcfsArpWithArpScanCommandMacAddressResolver>()
+ );
+ }
+
+ if (ProcfsArpWithNmapCommandMacAddressResolver.IsSupported) {
+ return new ProcfsArpWithNmapCommandMacAddressResolver(
+ options: options,
+ logger: serviceProvider?.GetService<ILoggerFactory>()?.CreateLogger<ProcfsArpWithNmapCommandMacAddressResolver>()
);
}
@@ -62,6 +72,9 @@ internal partial class ProcfsArpMacAddressResolver : MacAddressResolver {
public override bool HasInvalidated => !(invalidatedIPAddressSet.IsEmpty && invalidatedMacAddressSet.IsEmpty);
+ private SemaphoreSlim arpFullScanMutex = new(initialCount: 1, maxCount: 1);
+ private SemaphoreSlim arpPartialScanMutex = new(initialCount: ArpScanParallelMax, maxCount: ArpScanParallelMax);
+
public ProcfsArpMacAddressResolver(
MacAddressResolverOptions options,
ILogger? logger
@@ -71,6 +84,17 @@ internal partial class ProcfsArpMacAddressResolver : MacAddressResolver {
arpFullScanInterval = options.ProcfsArpFullScanInterval;
}
+ protected override void Dispose(bool disposing)
+ {
+ arpFullScanMutex?.Dispose();
+ arpFullScanMutex = null!;
+
+ arpPartialScanMutex?.Dispose();
+ arpPartialScanMutex = null!;
+
+ base.Dispose(disposing);
+ }
+
protected override async ValueTask<PhysicalAddress?> ResolveIPAddressToMacAddressAsyncCore(
IPAddress ipAddress,
CancellationToken cancellationToken
@@ -141,11 +165,11 @@ internal partial class ProcfsArpMacAddressResolver : MacAddressResolver {
: priorCandidate.IPAddress;
}
- protected override void InvalidateCore(IPAddress resolvedIPAddress)
- => invalidatedIPAddressSet.Add(resolvedIPAddress);
+ protected override void InvalidateCore(IPAddress ipAddress)
+ => invalidatedIPAddressSet.Add(ipAddress);
- protected override void InvalidateCore(PhysicalAddress resolvedMacAddress)
- => invalidatedMacAddressSet.Add(resolvedMacAddress);
+ protected override void InvalidateCore(PhysicalAddress macAddress)
+ => invalidatedMacAddressSet.Add(macAddress);
protected override ValueTask RefreshCacheAsyncCore(
CancellationToken cancellationToken = default
@@ -161,8 +185,16 @@ internal partial class ProcfsArpMacAddressResolver : MacAddressResolver {
private async ValueTask ArpFullScanAsync(CancellationToken cancellationToken)
{
- Logger?.LogDebug("Performing ARP full scan");
+ if (!await arpFullScanMutex.WaitAsync(0, cancellationToken: default).ConfigureAwait(false)) {
+ Logger?.LogInformation("ARP full scan is currently being performed.");
+ return;
+ }
+
+ Logger?.LogInformation("Performing ARP full scan.");
+ var sw = Logger is null ? null : Stopwatch.StartNew();
+
+ try {
await ArpFullScanAsyncCore(cancellationToken: cancellationToken).ConfigureAwait(false);
invalidatedIPAddressSet.Clear();
@@ -170,6 +202,12 @@ internal partial class ProcfsArpMacAddressResolver : MacAddressResolver {
lastArpFullScanAt = DateTime.Now;
}
+ finally {
+ Logger?.LogInformation("ARP full scan finished in {ElapsedMilliseconds} ms.", sw!.ElapsedMilliseconds);
+
+ arpFullScanMutex.Release();
+ }
+ }
protected virtual ValueTask ArpFullScanAsyncCore(CancellationToken cancellationToken)
{
@@ -192,29 +230,44 @@ internal partial class ProcfsArpMacAddressResolver : MacAddressResolver {
private async ValueTask ArpScanAsync(CancellationToken cancellationToken)
{
- Logger?.LogDebug("Performing ARP scan for invalidated targets.");
-
var invalidatedIPAddresses = invalidatedIPAddressSet.Keys;
var invalidatedMacAddresses = invalidatedMacAddressSet.Keys;
Logger?.LogTrace("Invalidated IP addresses: {InvalidatedIPAddresses}", string.Join(" ", invalidatedIPAddresses));
Logger?.LogTrace("Invalidated MAC addresses: {InvalidatedMACAddresses}", string.Join(" ", invalidatedMacAddresses));
+ if (invalidatedMacAddresses.Any()) {
+ // perform full scan
+ await ArpFullScanAsync(
+ cancellationToken: cancellationToken
+ ).ConfigureAwait(false);
+
+ return;
+ }
+
+ await arpPartialScanMutex.WaitAsync(cancellationToken: cancellationToken).ConfigureAwait(false);
+
+ var sw = Logger is null ? null : Stopwatch.StartNew();
+
+ try {
+ Logger?.LogInformation("Performing ARP scan for the invalidated {Count} IP addresses.", invalidatedIPAddresses.Count);
+
await ArpScanAsyncCore(
invalidatedIPAddresses: invalidatedIPAddresses,
- invalidatedMacAddresses: invalidatedMacAddresses,
cancellationToken: cancellationToken
).ConfigureAwait(false);
invalidatedIPAddressSet.Clear();
- invalidatedMacAddressSet.Clear();
+ }
+ finally {
+ Logger?.LogInformation("ARP scan finished in {ElapsedMilliseconds} ms.", sw!.ElapsedMilliseconds);
- lastArpFullScanAt = DateTime.Now;
+ arpPartialScanMutex.Release();
+ }
}
protected virtual ValueTask ArpScanAsyncCore(
IEnumerable<IPAddress> invalidatedIPAddresses,
- IEnumerable<PhysicalAddress> invalidatedMacAddresses,
CancellationToken cancellationToken
)
{
diff --git a/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.Arp/ProcfsArpWithArpScanCommandMacAddressResolver.cs b/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.Arp/ProcfsArpWithArpScanCommandMacAddressResolver.cs
new file mode 100644
index 0000000..a838136
--- /dev/null
+++ b/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.Arp/ProcfsArpWithArpScanCommandMacAddressResolver.cs
@@ -0,0 +1,171 @@
+// SPDX-FileCopyrightText: 2023 smdn <smdn@smdn.jp>
+// SPDX-License-Identifier: MIT
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Net;
+using System.Threading;
+using System.Threading.Tasks;
+using Microsoft.Extensions.Logging;
+
+namespace Smdn.Net.AddressResolution.Arp;
+
+internal sealed class ProcfsArpWithArpScanCommandMacAddressResolver : ProcfsArpMacAddressResolver {
+ // ref: https://manpages.ubuntu.com/manpages/jammy/man1/arp-scan.1.html
+ // --numeric: IP addresses only, no hostnames.
+ // --quiet: Only display minimal output. No protocol decoding.
+ private const string ArpScanCommandBaseOptions = "--numeric --quiet ";
+
+ public static new bool IsSupported =>
+ ProcfsArpMacAddressResolver.IsSupported &&
+ lazyPathToArpScanCommand.Value is not null &&
+#pragma warning disable IDE0047, SA1119
+ (
+#if NET8_0_OR_GREATER
+ Environment.IsPrivilegedProcess ||
+#endif
+#if NET7_0_OR_GREATER
+ HasSgidOrSuid(File.GetUnixFileMode(lazyPathToArpScanCommand.Value))
+#else
+ false // TODO: use Mono.Posix
+#endif
+ );
+#pragma warning restore IDE0047, SA1119
+
+#if NET7_0_OR_GREATER
+ private static bool HasSgidOrSuid(UnixFileMode fileMode)
+ => fileMode.HasFlag(UnixFileMode.SetGroup) || fileMode.HasFlag(UnixFileMode.SetUser);
+#endif
+
+ private static readonly Lazy<string?> lazyPathToArpScanCommand = new(valueFactory: GetPathToArpScanCommand, isThreadSafe: true);
+ private static readonly string[] BinDirs = new[] { "/sbin/", "/usr/sbin/", "/bin/", "/usr/bin/" };
+
+ private static string? GetPathToArpScanCommand()
+ => BinDirs
+ .Select(static dir => Path.Combine(dir, "arp-scan"))
+ .FirstOrDefault(static pathToArpScanCommand => File.Exists(pathToArpScanCommand));
+
+ /*
+ * instance members
+ */
+ private readonly string arpScanCommandCommonOptions;
+ private readonly string arpScanCommandFullScanOptions;
+
+ public ProcfsArpWithArpScanCommandMacAddressResolver(
+ MacAddressResolverOptions options,
+ ILogger? logger
+ )
+ : base(
+ options,
+ logger
+ )
+ {
+ arpScanCommandCommonOptions = ArpScanCommandBaseOptions;
+
+ if (!string.IsNullOrEmpty(options.ArpScanCommandInterfaceSpecification))
+ arpScanCommandCommonOptions += $"--interface={options.ArpScanCommandInterfaceSpecification} ";
+
+ arpScanCommandFullScanOptions = string.Concat(
+ arpScanCommandCommonOptions,
+ // ref: https://manpages.ubuntu.com/manpages/jammy/man1/arp-scan.1.html
+ // --localnet: Generate addresses from network interface configuration.
+ options.ArpScanCommandTargetSpecification ?? "--localnet "
+ );
+ }
+
+ protected override ValueTask ArpFullScanAsyncCore(CancellationToken cancellationToken)
+ // perform full scan
+ => RunArpScanCommandAsync(
+ arpScanCommandOptions: arpScanCommandFullScanOptions,
+ logger: Logger,
+ cancellationToken: cancellationToken
+ );
+
+ protected override ValueTask ArpScanAsyncCore(
+ IEnumerable<IPAddress> invalidatedIPAddresses,
+ CancellationToken cancellationToken
+ )
+ {
+ // perform scan for specific target IPs
+ var arpScanCommandTargetSpecification = string.Join(" ", invalidatedIPAddresses);
+
+ return arpScanCommandTargetSpecification.Length == 0
+ ? default // do nothing
+ : RunArpScanCommandAsync(
+ arpScanCommandOptions: arpScanCommandCommonOptions + arpScanCommandTargetSpecification,
+ logger: Logger,
+ cancellationToken: cancellationToken
+ );
+ }
+
+ private static async ValueTask RunArpScanCommandAsync(
+ string arpScanCommandOptions,
+ ILogger? logger,
+ CancellationToken cancellationToken
+ )
+ {
+ var arpScanCommandProcessStartInfo = new ProcessStartInfo() {
+ FileName = lazyPathToArpScanCommand.Value,
+ Arguments = arpScanCommandOptions,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ };
+
+ logger?.LogDebug(
+ "[arp-scan] {ProcessStartInfoFileName} {ProcessStartInfoArguments}",
+ arpScanCommandProcessStartInfo.FileName,
+ arpScanCommandProcessStartInfo.Arguments
+ );
+
+ using var arpScanProcess = new Process() {
+ StartInfo = arpScanCommandProcessStartInfo,
+ };
+
+ try {
+ arpScanProcess.Start();
+
+#if SYSTEM_DIAGNOSTICS_PROCESS_WAITFOREXITASYNC
+ await arpScanProcess.WaitForExitAsync(cancellationToken).ConfigureAwait(false);
+#else
+ arpScanProcess.WaitForExit(); // TODO: cacellation
+#endif
+
+ if (logger is not null) {
+ const LogLevel logLevelForStandardOutput = LogLevel.Trace;
+ const LogLevel logLevelForStandardError = LogLevel.Error;
+
+ static IEnumerable<(StreamReader, LogLevel)> EnumerateLogTarget(StreamReader stdout, StreamReader stderr)
+ {
+ yield return (stdout, logLevelForStandardOutput);
+ yield return (stderr, logLevelForStandardError);
+ }
+
+ foreach (var (stdio, logLevel) in EnumerateLogTarget(arpScanProcess.StandardOutput, arpScanProcess.StandardError)) {
+ if (!logger.IsEnabled(logLevel))
+ continue;
+
+ for (; ;) {
+ var line = await stdio.ReadLineAsync().ConfigureAwait(false);
+
+ if (line is null)
+ break;
+
+ logger.Log(logLevel, "[arp-scan] {Line}", line);
+ }
+ }
+
+ if (!logger.IsEnabled(LogLevel.Error))
+ logger.LogDebug("[arp-scan] process exited with code {ExitCode}", arpScanProcess.ExitCode);
+ }
+
+ if (arpScanProcess.ExitCode != 0)
+ logger?.LogError("[arp-scan] process exited with code {ExitCode}", arpScanProcess.ExitCode);
+ }
+ catch (Exception ex) {
+ logger?.LogError(ex, "[arp-scan] failed to perform ARP scanning");
+ }
+ }
+}
diff --git a/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.Arp/ProcfsArpNmapScanMacAddressResolver.cs b/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.Arp/ProcfsArpWithNmapCommandMacAddressResolver.cs
similarity index 53%
rename from src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.Arp/ProcfsArpNmapScanMacAddressResolver.cs
rename to src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.Arp/ProcfsArpWithNmapCommandMacAddressResolver.cs
index 983f739..508e2a5 100644
--- a/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.Arp/ProcfsArpNmapScanMacAddressResolver.cs
+++ b/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.Arp/ProcfsArpWithNmapCommandMacAddressResolver.cs
@@ -6,20 +6,27 @@ using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
-using System.Net.NetworkInformation;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.Logging;
namespace Smdn.Net.AddressResolution.Arp;
-internal sealed class ProcfsArpNmapScanMacAddressResolver : ProcfsArpMacAddressResolver {
- public static new bool IsSupported => ProcfsArpMacAddressResolver.IsSupported && lazyPathToNmap.Value is not null;
+internal sealed class ProcfsArpWithNmapCommandMacAddressResolver : ProcfsArpMacAddressResolver {
+ // ref: https://nmap.org/book/man-briefoptions.html
+ // -sn: Ping Scan - disable port scan
+ // -n: Never do DNS resolution
+ // -T<0-5>: Set timing template (higher is faster)
+ // 4 = aggressive
+ // -oG <file>: Output scan in Grepable format
+ private const string NmapCommandBaseOptions = "-sn -n -T4 -oG - ";
+
+ public static new bool IsSupported => ProcfsArpMacAddressResolver.IsSupported && lazyPathToNmapCommand.Value is not null;
- private static readonly Lazy<string?> lazyPathToNmap = new(valueFactory: GetPathToNmap, isThreadSafe: true);
+ private static readonly Lazy<string?> lazyPathToNmapCommand = new(valueFactory: GetPathToNmapCommand, isThreadSafe: true);
private static readonly string[] BinDirs = new[] { "/bin/", "/sbin/", "/usr/bin/" };
- private static string? GetPathToNmap()
+ private static string? GetPathToNmapCommand()
=> BinDirs
.Select(static dir => Path.Combine(dir, "nmap"))
.FirstOrDefault(static nmap => File.Exists(nmap));
@@ -27,9 +34,10 @@ internal sealed class ProcfsArpNmapScanMacAddressResolver : ProcfsArpMacAddressR
/*
* instance members
*/
- private readonly string nmapTargetSpecification;
+ private readonly string nmapCommandCommonOptions;
+ private readonly string nmapCommandFullScanOptions;
- public ProcfsArpNmapScanMacAddressResolver(
+ public ProcfsArpWithNmapCommandMacAddressResolver(
MacAddressResolverOptions options,
ILogger? logger
)
@@ -38,60 +46,53 @@ internal sealed class ProcfsArpNmapScanMacAddressResolver : ProcfsArpMacAddressR
logger
)
{
- nmapTargetSpecification = options.NmapTargetSpecification
- ?? throw new ArgumentException($"{nameof(options.NmapTargetSpecification)} must be specified with {nameof(MacAddressResolverOptions)}");
+ if (string.IsNullOrEmpty(options.NmapCommandInterfaceSpecification))
+ nmapCommandCommonOptions = NmapCommandBaseOptions;
+ else
+ // -e <iface>: Use specified interface
+ nmapCommandCommonOptions = NmapCommandBaseOptions + $"-e {options.NmapCommandInterfaceSpecification} ";
+
+ nmapCommandFullScanOptions = string.Concat(
+ nmapCommandCommonOptions,
+ options.NmapCommandTargetSpecification
+ ?? throw new ArgumentException($"{nameof(options.NmapCommandTargetSpecification)} must be specified with {nameof(MacAddressResolverOptions)}")
+ );
}
protected override ValueTask ArpFullScanAsyncCore(CancellationToken cancellationToken)
- => NmapScanAsync(
- nmapOptionTargetSpecification: nmapTargetSpecification,
+ // perform full scan
+ => RunNmapCommandAsync(
+ nmapCommandOptions: nmapCommandFullScanOptions,
logger: Logger,
cancellationToken: cancellationToken
);
protected override ValueTask ArpScanAsyncCore(
IEnumerable<IPAddress> invalidatedIPAddresses,
- IEnumerable<PhysicalAddress> invalidatedMacAddresses,
CancellationToken cancellationToken
)
{
- if (invalidatedMacAddresses.Any()) {
- // perform full scan
- return NmapScanAsync(
- nmapOptionTargetSpecification: nmapTargetSpecification,
- logger: Logger,
- cancellationToken: cancellationToken
- );
- }
-
// perform scan for specific target IPs
- var nmapOptionTargetSpecification = string.Join(" ", invalidatedIPAddresses);
+ var nmapCommandOptionTargetSpecification = string.Join(" ", invalidatedIPAddresses);
- return nmapOptionTargetSpecification.Length == 0
+ return nmapCommandOptionTargetSpecification.Length == 0
? default // do nothing
- : NmapScanAsync(
- nmapOptionTargetSpecification: nmapOptionTargetSpecification,
+ : RunNmapCommandAsync(
+ nmapCommandOptions: nmapCommandCommonOptions + nmapCommandOptionTargetSpecification,
logger: Logger,
cancellationToken: cancellationToken
);
}
- private static async ValueTask NmapScanAsync(
- string nmapOptionTargetSpecification,
+ private static async ValueTask RunNmapCommandAsync(
+ string nmapCommandOptions,
ILogger? logger,
CancellationToken cancellationToken
)
{
- // -sn: Ping Scan - disable port scan
- // -n: Never do DNS resolution
- // -T<0-5>: Set timing template (higher is faster)
- // 4 = aggressive
- // -oG <file>: Output scan in Grepable format
- const string nmapOptions = "-sn -n -T4 -oG - ";
-
- var nmapProcessStartInfo = new ProcessStartInfo() {
- FileName = lazyPathToNmap.Value,
- Arguments = nmapOptions + nmapOptionTargetSpecification,
+ var nmapCommandProcessStartInfo = new ProcessStartInfo() {
+ FileName = lazyPathToNmapCommand.Value,
+ Arguments = nmapCommandOptions,
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
@@ -99,12 +100,12 @@ internal sealed class ProcfsArpNmapScanMacAddressResolver : ProcfsArpMacAddressR
logger?.LogDebug(
"[nmap] {ProcessStartInfoFileName} {ProcessStartInfoArguments}",
- nmapProcessStartInfo.FileName,
- nmapProcessStartInfo.Arguments
+ nmapCommandProcessStartInfo.FileName,
+ nmapCommandProcessStartInfo.Arguments
);
using var nmapProcess = new Process() {
- StartInfo = nmapProcessStartInfo,
+ StartInfo = nmapCommandProcessStartInfo,
};
try {
@@ -139,7 +140,13 @@ internal sealed class ProcfsArpNmapScanMacAddressResolver : ProcfsArpMacAddressR
logger.Log(logLevel, "[nmap] {Line}", line);
}
}
+
+ if (!logger.IsEnabled(LogLevel.Error))
+ logger.LogDebug("[nmap] process exited with code {ExitCode}", nmapProcess.ExitCode);
}
+
+ if (nmapProcess.ExitCode != 0)
+ logger?.LogError("[nmap] process exited with code {ExitCode}", nmapProcess.ExitCode);
}
catch (Exception ex) {
logger?.LogError(ex, "[nmap] failed to perform ARP scanning");
diff --git a/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.csproj b/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.csproj
index c23de68..7597ef5 100644
--- a/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.csproj
+++ b/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution.csproj
@@ -5,8 +5,10 @@ SPDX-License-Identifier: MIT
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netstandard2.0;netstandard2.1;net6.0</TargetFrameworks>
+ <TargetFrameworks Condition="$([MSBuild]::VersionGreaterThanOrEquals('$(NETCoreSdkVersion)', '7.0.0'))">net7.0;$(TargetFrameworks)</TargetFrameworks>
+ <TargetFrameworks Condition="$([MSBuild]::VersionGreaterThanOrEquals('$(NETCoreSdkVersion)', '8.0.0'))">net8.0;$(TargetFrameworks)</TargetFrameworks>
<VersionPrefix>1.0.0</VersionPrefix>
- <VersionSuffix>preview4</VersionSuffix>
+ <VersionSuffix>preview5</VersionSuffix>
<!-- <PackageValidationBaselineVersion>1.0.0</PackageValidationBaselineVersion> -->
<Nullable>enable</Nullable>
<NoWarn>CA1848</NoWarn> <!-- use the LoggerMessage delegates instead -->
@@ -25,6 +27,10 @@ This library provides interfaces for resolving between IP addresses and MAC addr
<PackageTags>ARP;ip-address;mac-address;hardware-address;address-lookup;address-resolution</PackageTags>
</PropertyGroup>
+ <PropertyGroup Label="StyleCop code analysis">
+ <StyleCopAnalyzersConfigurationFile>stylecop.json</StyleCopAnalyzersConfigurationFile>
+ </PropertyGroup>
+
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Logging" Version="6.0.0" />
</ItemGroup>
diff --git a/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution/IAddressResolver.cs b/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution/IAddressResolver.cs
index b172e3d..8504fbc 100644
--- a/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution/IAddressResolver.cs
+++ b/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution/IAddressResolver.cs
@@ -8,5 +8,5 @@ namespace Smdn.Net.AddressResolution;
public interface IAddressResolver<TAddress, TResolvedAddress> {
/// <returns>An resolved address. <see langword="null"/> if address could not be resolved.</returns>
public ValueTask<TResolvedAddress?> ResolveAsync(TAddress address, CancellationToken cancellationToken);
- public void Invalidate(TResolvedAddress resolvedAddress);
+ public void Invalidate(TAddress address);
}
diff --git a/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution/MacAddressResolver.cs b/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution/MacAddressResolver.cs
index b9b01c5..7793db5 100644
--- a/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution/MacAddressResolver.cs
+++ b/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution/MacAddressResolver.cs
@@ -83,9 +83,9 @@ public abstract class MacAddressResolver :
);
void IAddressResolver<IPAddress, PhysicalAddress>.Invalidate(
- PhysicalAddress resolvedAddress
+ IPAddress address
)
- => Invalidate(resolvedMacAddress: resolvedAddress);
+ => Invalidate(ipAddress: address);
#pragma warning disable SA1305
public ValueTask<PhysicalAddress?> ResolveIPAddressToMacAddressAsync(
@@ -131,19 +131,19 @@ public abstract class MacAddressResolver :
);
#pragma warning restore SA1305
- public void Invalidate(PhysicalAddress resolvedMacAddress)
+ public void Invalidate(IPAddress ipAddress)
{
- if (resolvedMacAddress is null)
- throw new ArgumentNullException(nameof(resolvedMacAddress));
+ if (ipAddress is null)
+ throw new ArgumentNullException(nameof(ipAddress));
ThrowIfDisposed();
- Logger?.LogDebug("Invalidating {MacAddress}", resolvedMacAddress.ToMacAddressString());
+ Logger?.LogDebug("Invalidating {IPAddress}", ipAddress);
- InvalidateCore(resolvedMacAddress);
+ InvalidateCore(ipAddress);
}
- protected abstract void InvalidateCore(PhysicalAddress resolvedMacAddress);
+ protected abstract void InvalidateCore(IPAddress ipAddress);
/*
* PhysicalAddress -> IPAddress
@@ -158,9 +158,9 @@ public abstract class MacAddressResolver :
);
void IAddressResolver<PhysicalAddress, IPAddress>.Invalidate(
- IPAddress resolvedAddress
+ PhysicalAddress address
)
- => Invalidate(resolvedIPAddress: resolvedAddress);
+ => Invalidate(macAddress: address);
public ValueTask<IPAddress?> ResolveMacAddressToIPAddressAsync(
PhysicalAddress macAddress,
@@ -209,19 +209,19 @@ public abstract class MacAddressResolver :
CancellationToken cancellationToken
);
- public void Invalidate(IPAddress resolvedIPAddress)
+ public void Invalidate(PhysicalAddress macAddress)
{
- if (resolvedIPAddress is null)
- throw new ArgumentNullException(nameof(resolvedIPAddress));
+ if (macAddress is null)
+ throw new ArgumentNullException(nameof(macAddress));
ThrowIfDisposed();
- Logger?.LogDebug("Invalidating {IPAddress}", resolvedIPAddress);
+ Logger?.LogDebug("Invalidating {IPAddress}", macAddress.ToMacAddressString());
- InvalidateCore(resolvedIPAddress);
+ InvalidateCore(macAddress);
}
- protected abstract void InvalidateCore(IPAddress resolvedIPAddress);
+ protected abstract void InvalidateCore(PhysicalAddress macAddress);
/*
* other virtual/abstract members
diff --git a/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution/MacAddressResolverOptions.cs b/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution/MacAddressResolverOptions.cs
index 9525810..d2cd901 100644
--- a/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution/MacAddressResolverOptions.cs
+++ b/src/Smdn.Net.AddressResolution/Smdn.Net.AddressResolution/MacAddressResolverOptions.cs
@@ -7,10 +7,25 @@ namespace Smdn.Net.AddressResolution;
public sealed class MacAddressResolverOptions {
public static readonly MacAddressResolverOptions Default = new() { };
+ /// <summary>
+ /// Gets the string value passed to the argument '-e <iface>' of nmap command.
+ /// </summary>
+ public string? NmapCommandInterfaceSpecification { get; init; }
+
/// <summary>
/// Gets the string value passed to the argument <target specification> of nmap command.
/// </summary>
- public string? NmapTargetSpecification { get; init; }
+ public string? NmapCommandTargetSpecification { get; init; }
+
+ /// <summary>
+ /// Gets the string value passed to the argument '--interface=<s≫' of arp-scan command.
+ /// </summary>
+ public string? ArpScanCommandInterfaceSpecification { get; init; }
+
+ /// <summary>
+ /// Gets the string value represents the 'target hosts' pass to the arp-scan command. This value can be IP addresses or hostnames.
+ /// </summary>
+ public string? ArpScanCommandTargetSpecification { get; init; }
public TimeSpan ProcfsArpFullScanInterval { get; init; } = TimeSpan.FromMinutes(15.0);
}
diff --git a/src/Smdn.Net.AddressResolution/stylecop.json b/src/Smdn.Net.AddressResolution/stylecop.json
new file mode 100644
index 0000000..39c1bb6
--- /dev/null
+++ b/src/Smdn.Net.AddressResolution/stylecop.json
@@ -0,0 +1,18 @@
+{
+ "settings": {
+ "indentation": {
+ "indentationSize": 2,
+ "tabSize": 2,
+ "useTabs": false
+ },
+ "maintainabilityRules": {
+ "topLevelTypes": ["class", "struct", "interface", "delegate", "enum"]
+ },
+ "namingRules": {
+ "allowedHungarianPrefixes": ["ex", "ip"]
+ },
+ "documentationRules": {
+ "xmlHeader": false
+ }
+ }
+}
Notes
Full Changelog: releases/Smdn.Net.AddressResolution-1.0.0-preview4...releases/Smdn.Net.AddressResolution-1.0.0-preview5