From b9bf88be67f0f82b942920177f922a07a3722d97 Mon Sep 17 00:00:00 2001 From: Eric Williams <53901011+ewilliams0305@users.noreply.github.com> Date: Tue, 5 Mar 2024 09:25:16 -0500 Subject: [PATCH 1/4] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d0f7700..332a7cd 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![Readme Image](../../docs/kangaroo-header.png) +![Readme Image](./../docs/kangaroo-header.png) # kangaroo Network Scanner ![GitHub](https://img.shields.io/github/license/ewilliams0305/kangaroo) From f311735b32b1fd4f7bd524fcb4d6769b4056f8db Mon Sep 17 00:00:00 2001 From: Eric Williams <53901011+ewilliams0305@users.noreply.github.com> Date: Tue, 5 Mar 2024 09:27:34 -0500 Subject: [PATCH 2/4] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 332a7cd..f49dc91 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -![Readme Image](./../docs/kangaroo-header.png) +![Readme Image](./docs/kangaroo-header.png) # kangaroo Network Scanner ![GitHub](https://img.shields.io/github/license/ewilliams0305/kangaroo) From 7fc496ab0a2e84a6c2bfb2aa974b44d96d50ac57 Mon Sep 17 00:00:00 2001 From: Eric Williams Date: Tue, 5 Mar 2024 09:30:39 -0500 Subject: [PATCH 3/4] clean up --- source/Kangaroo.CLI/Commands/IpScanCommand.cs | 83 ++++++++----------- source/Kangaroo/Model/MacAddress.cs | 2 - 2 files changed, 36 insertions(+), 49 deletions(-) diff --git a/source/Kangaroo.CLI/Commands/IpScanCommand.cs b/source/Kangaroo.CLI/Commands/IpScanCommand.cs index 149775e..6d60687 100644 --- a/source/Kangaroo.CLI/Commands/IpScanCommand.cs +++ b/source/Kangaroo.CLI/Commands/IpScanCommand.cs @@ -1,58 +1,47 @@ using Cocona; using Dumpify; using Microsoft.Extensions.Logging; -using System.Net; -namespace Kangaroo.CLI.Commands +namespace Kangaroo.CLI.Commands; + +public sealed class IpScanCommand(ILogger logger, IScannerIpConfiguration config) { - public sealed class IpScanCommand + [Command("scan", Description = "Scans the configured range of IP addresses")] + public async Task ScanNetwork([Option(shortName: 's')] string start, [Option(shortName: 'e')] string end, [Option(shortName: 't')] int? timeout) { - private readonly ILogger _logger; - private readonly IScannerIpConfiguration _config; - - public IpScanCommand(ILogger logger, IScannerIpConfiguration config) - { - _logger = logger; - _config = config; - } - - [Command("scan", Description = "Scans the configured range of IP addresses")] - public async Task ScanNetwork([Option(shortName: 's')] string start, [Option(shortName: 'e')] string end, [Option(shortName: 't')] int? timeout) - { - var scanner = _config - - .WithRange(start, end) - .WithMaxTimeout(TimeSpan.FromMilliseconds(timeout ?? 1000)) - .WithMaxHops(4) - .WithParallelism(10) - .WithLogging(_logger) - .Build(); - - var results = await scanner.QueryAddresses(); - var output = results.Nodes - .Where(n => n.Alive) - .Select(n => new - { - IPAddress = n.IpAddress.ToString(), - MacAddress = n.MacAddress.ToString(), - Hostname = n.HostName, - Latency = n.Latency.ToString(), - QueryTime = n.QueryTime.ToString(), - }) - .ToList(); - - new + var scanner = config + + .WithRange(start, end) + .WithMaxTimeout(TimeSpan.FromMilliseconds(timeout ?? 1000)) + .WithMaxHops(4) + .WithParallelism(10) + .WithLogging(logger) + .Build(); + + var results = await scanner.QueryAddresses(); + var output = results.Nodes + .Where(n => n.Alive) + .Select(n => new { - Scanned = $"{results.NumberOfAliveNodes} UP / {results.NumberOfAddressesScanned}" , - ElapsedTime = results.ElapsedTime.ToString(), - StartAddress = results.StartAddress.ToString(), - EndAddress = results.EndAddress.ToString() + IPAddress = n.IpAddress.ToString(), + MacAddress = n.MacAddress.ToString(), + Hostname = n.HostName, + Latency = n.Latency.ToString(), + QueryTime = n.QueryTime.ToString(), + }) + .ToList(); + + new + { + Scanned = $"{results.NumberOfAliveNodes} UP / {results.NumberOfAddressesScanned}" , + ElapsedTime = results.ElapsedTime.ToString(), + StartAddress = results.StartAddress.ToString(), + EndAddress = results.EndAddress.ToString() - }.Dump("SCANNER RESULTS", typeNames: new TypeNamingConfig { ShowTypeNames = false }); + }.Dump("SCANNER RESULTS", typeNames: new TypeNamingConfig { ShowTypeNames = false }); - output.Dump("NETWORK NODES LOCATED", typeNames: new TypeNamingConfig { ShowTypeNames = false }); + output.Dump("NETWORK NODES LOCATED", typeNames: new TypeNamingConfig { ShowTypeNames = false }); - return 0; - } + return 0; } -} +} \ No newline at end of file diff --git a/source/Kangaroo/Model/MacAddress.cs b/source/Kangaroo/Model/MacAddress.cs index 9c78394..dd7e9c3 100644 --- a/source/Kangaroo/Model/MacAddress.cs +++ b/source/Kangaroo/Model/MacAddress.cs @@ -87,8 +87,6 @@ public MacAddress(string macAddress) { throw new ArgumentOutOfRangeException(nameof(macAddress)); } - var b = new byte(); - _bytes = bytes; } From ecf82bbc8585ac5b0a19d8bbf902cc67bb2ad1d9 Mon Sep 17 00:00:00 2001 From: Eric Williams Date: Tue, 5 Mar 2024 11:51:39 -0500 Subject: [PATCH 4/4] created additional console commands closes #15 closes #14 --- .../Commands/AdapterScanCommand.cs | 88 +++++++++++++++++++ source/Kangaroo.CLI/Commands/IpScanCommand.cs | 47 ---------- .../Kangaroo.CLI/Commands/RangeScanCommand.cs | 48 ++++++++++ .../Commands/SubnetScanCommand.cs | 49 +++++++++++ source/Kangaroo.CLI/Kangaroo.CLI.csproj | 2 +- source/Kangaroo.CLI/OutputExtensions.cs | 65 ++++++++++++++ source/Kangaroo.CLI/Program.cs | 4 +- .../Properties/launchSettings.json | 12 ++- .../Exceptions/InvalidIpRangeException.cs | 2 +- .../InvalidNetworkAdapterException.cs | 2 +- .../Exceptions/InvalidSubnetException.cs | 2 +- .../Exceptions/InvalidTimeoutException.cs | 2 +- .../Builder/Exceptions/InvalidTtlException.cs | 2 +- .../Builder/Options/ScannerOptions.cs | 6 ++ .../Builder/Pipeline/IScannerBuilder.cs | 19 ++-- .../Builder/Pipeline/ScannerBuilder.cs | 26 ++++-- source/Kangaroo/Kangaroo.csproj | 2 +- source/Kangaroo/Model/NetworkNode.cs | 3 +- source/Kangaroo/Queries/IQueryWebServer.cs | 8 ++ source/Kangaroo/Queries/QueryHostname.cs | 9 +- source/Kangaroo/Queries/QueryNetworkNode.cs | 10 ++- source/Kangaroo/Queries/QueryWebServer.cs | 39 ++++++++ 22 files changed, 369 insertions(+), 78 deletions(-) create mode 100644 source/Kangaroo.CLI/Commands/AdapterScanCommand.cs delete mode 100644 source/Kangaroo.CLI/Commands/IpScanCommand.cs create mode 100644 source/Kangaroo.CLI/Commands/RangeScanCommand.cs create mode 100644 source/Kangaroo.CLI/Commands/SubnetScanCommand.cs create mode 100644 source/Kangaroo.CLI/OutputExtensions.cs create mode 100644 source/Kangaroo/Queries/IQueryWebServer.cs create mode 100644 source/Kangaroo/Queries/QueryWebServer.cs diff --git a/source/Kangaroo.CLI/Commands/AdapterScanCommand.cs b/source/Kangaroo.CLI/Commands/AdapterScanCommand.cs new file mode 100644 index 0000000..37c29ee --- /dev/null +++ b/source/Kangaroo.CLI/Commands/AdapterScanCommand.cs @@ -0,0 +1,88 @@ +using System.Net.NetworkInformation; +using Cocona; +using Dumpify; +using Microsoft.Extensions.Logging; + +namespace Kangaroo.CLI.Commands; + +public sealed class AdapterScanCommand(ILogger logger, IScannerIpConfiguration config) +{ + + [Command("adapter", Aliases = ["a"],Description = "Scans IP address using the subnet on the provided adapter")] + public async ValueTask QueryAdapter( + [Option( + shortName: 'a', + Description = "The network adapter to scan", + ValueName = "adapter")] string? adapter , + [Option( + shortName: 't', + Description = "Query timeout in milliseconds", + ValueName = "timeout")] int? timeout)=> + adapter == null + ? QueryAdapters() + : await ScanAdapter(adapter, timeout); + + private int QueryAdapters() + { + var interfaces = NetworkInterface.GetAllNetworkInterfaces(); + + foreach (var @interface in interfaces) + { + if (@interface.OperationalStatus != OperationalStatus.Up && + @interface.NetworkInterfaceType != NetworkInterfaceType.Loopback && + @interface.NetworkInterfaceType != NetworkInterfaceType.Tunnel) + { + continue; + } + + var ipProps = @interface.GetIPProperties(); + foreach (var ip in ipProps.UnicastAddresses) + { + if (ip.Address.AddressFamily != System.Net.Sockets.AddressFamily.InterNetwork) + { + continue; + } + + @interface.DumpInterface(ip); + } + } + return 0; + } + + public async Task ScanAdapter(string adapterName, int? timeout) + { + try + { + var adapter = NetworkInterface + .GetAllNetworkInterfaces() + .FirstOrDefault(n => + n.Name.ToLower().Replace(" ", "") == + adapterName.ToLower().Replace(" ", "")); + + if (adapter == null) + { + Console.WriteLine($"Invalid Network Adapter Specified {adapterName}"); + return -1; + } + var scanner = config + .WithInterface(adapter) + .WithHttpScan(() => new HttpClient()) + .WithMaxTimeout(TimeSpan.FromMilliseconds(timeout ?? 1000)) + .WithMaxHops(4) + .WithParallelism(10) + .WithLogging(logger) + .Build(); + + var results = await scanner.QueryAddresses(); + results.DumpResults(); + return 0; + } + catch (InvalidSubnetException e) + { + e.Message.Dump(); + } + + return -1; + + } +} \ No newline at end of file diff --git a/source/Kangaroo.CLI/Commands/IpScanCommand.cs b/source/Kangaroo.CLI/Commands/IpScanCommand.cs deleted file mode 100644 index 6d60687..0000000 --- a/source/Kangaroo.CLI/Commands/IpScanCommand.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Cocona; -using Dumpify; -using Microsoft.Extensions.Logging; - -namespace Kangaroo.CLI.Commands; - -public sealed class IpScanCommand(ILogger logger, IScannerIpConfiguration config) -{ - [Command("scan", Description = "Scans the configured range of IP addresses")] - public async Task ScanNetwork([Option(shortName: 's')] string start, [Option(shortName: 'e')] string end, [Option(shortName: 't')] int? timeout) - { - var scanner = config - - .WithRange(start, end) - .WithMaxTimeout(TimeSpan.FromMilliseconds(timeout ?? 1000)) - .WithMaxHops(4) - .WithParallelism(10) - .WithLogging(logger) - .Build(); - - var results = await scanner.QueryAddresses(); - var output = results.Nodes - .Where(n => n.Alive) - .Select(n => new - { - IPAddress = n.IpAddress.ToString(), - MacAddress = n.MacAddress.ToString(), - Hostname = n.HostName, - Latency = n.Latency.ToString(), - QueryTime = n.QueryTime.ToString(), - }) - .ToList(); - - new - { - Scanned = $"{results.NumberOfAliveNodes} UP / {results.NumberOfAddressesScanned}" , - ElapsedTime = results.ElapsedTime.ToString(), - StartAddress = results.StartAddress.ToString(), - EndAddress = results.EndAddress.ToString() - - }.Dump("SCANNER RESULTS", typeNames: new TypeNamingConfig { ShowTypeNames = false }); - - output.Dump("NETWORK NODES LOCATED", typeNames: new TypeNamingConfig { ShowTypeNames = false }); - - return 0; - } -} \ No newline at end of file diff --git a/source/Kangaroo.CLI/Commands/RangeScanCommand.cs b/source/Kangaroo.CLI/Commands/RangeScanCommand.cs new file mode 100644 index 0000000..28623b8 --- /dev/null +++ b/source/Kangaroo.CLI/Commands/RangeScanCommand.cs @@ -0,0 +1,48 @@ +using Cocona; +using Dumpify; +using Microsoft.Extensions.Logging; + +namespace Kangaroo.CLI.Commands; + +public sealed class RangeScanCommand(ILogger logger, IScannerIpConfiguration config) +{ + [Command("range", Description = "Scans the configured range of IP addresses")] + public async Task ScanNetwork( + [Option( + shortName: 's', + Description = "Starting IP address to begin scan with", + ValueName = "start")] string start, + [Option( + shortName: 'e', + Description = "Ending IP address to stop scan at", + ValueName = "end")] string end, + [Option( + shortName: 't', + Description = "Query timeout in milliseconds", + ValueName = "timeout")] int? timeout) + { + try + { + var scanner = config + + .WithRange(start, end) + .WithHttpScan(() => new HttpClient()) + .WithMaxTimeout(TimeSpan.FromMilliseconds(timeout ?? 1000)) + .WithMaxHops(4) + .WithParallelism(10) + .WithLogging(logger) + .Build(); + + var results = await scanner.QueryAddresses(); + results.DumpResults(); + return 0; + } + catch (InvalidIpRangeException e) + { + e.Message.Dump(); + } + + return -1; + + } +} \ No newline at end of file diff --git a/source/Kangaroo.CLI/Commands/SubnetScanCommand.cs b/source/Kangaroo.CLI/Commands/SubnetScanCommand.cs new file mode 100644 index 0000000..e59f7e3 --- /dev/null +++ b/source/Kangaroo.CLI/Commands/SubnetScanCommand.cs @@ -0,0 +1,49 @@ +using Cocona; +using Dumpify; +using Microsoft.Extensions.Logging; + +namespace Kangaroo.CLI.Commands; + +public sealed class SubnetScanCommand(ILogger logger, IScannerIpConfiguration config) +{ + [Command("subnet", Description = "Scans the configured subnet, note only /16 - /24 is currently available")] + public async Task ScanNetwork( + [Option( + shortName: 'i', + Description = "IP Address matching the subnet mask provided", + ValueName = "i")] string ip, + [Option( + shortName: 'm', + Description = "Subnet mask to determine IP range scope", + ValueName = "end")] string mask, + [Option( + shortName: 't', + Description = "Query timeout in milliseconds", + ValueName = "timeout")] int? timeout) + { + + try + { + var scanner = config + + .WithSubnet(ip, mask) + .WithHttpScan(() => new HttpClient()) + .WithMaxTimeout(TimeSpan.FromMilliseconds(timeout ?? 1000)) + .WithMaxHops(4) + .WithParallelism(10) + .WithLogging(logger) + .Build(); + + var results = await scanner.QueryAddresses(); + results.DumpResults(); + return 0; + } + catch (InvalidSubnetException e) + { + e.Message.Dump(); + } + + return -1; + + } +} \ No newline at end of file diff --git a/source/Kangaroo.CLI/Kangaroo.CLI.csproj b/source/Kangaroo.CLI/Kangaroo.CLI.csproj index 876b6e6..91f167a 100644 --- a/source/Kangaroo.CLI/Kangaroo.CLI.csproj +++ b/source/Kangaroo.CLI/Kangaroo.CLI.csproj @@ -11,7 +11,7 @@ True kangaroo ..\..\release - 0.0.2 + 0.0.3 Kangaroo CLI Tool A command line IP scanner diff --git a/source/Kangaroo.CLI/OutputExtensions.cs b/source/Kangaroo.CLI/OutputExtensions.cs new file mode 100644 index 0000000..db14356 --- /dev/null +++ b/source/Kangaroo.CLI/OutputExtensions.cs @@ -0,0 +1,65 @@ +using System.Net; +using System.Net.NetworkInformation; +using System.Net.Sockets; +using Dumpify; +using Kangaroo; + +namespace Kangaroo.CLI; + +public static class OutputExtensions +{ + public static void DumpNode(this IEnumerable nodes) + { + var output = nodes + .Where(n => n.Alive) + .Select(n => new + { + IPAddress = n.IpAddress.ToString(), + MacAddress = n.MacAddress.ToString(), + Hostname = n.HostName, + Latency = n.Latency.ToString(), + QueryTime = n.QueryTime.ToString(), + }) + .ToList(); + + output.Dump("NETWORK NODES LOCATED", typeNames: new TypeNamingConfig { ShowTypeNames = false }); + } + + public static void DumpResults(this ScanResults results) + { + var output = results.Nodes + .Where(n => n.Alive) + .Select(n => new + { + IPAddress = n.IpAddress.ToString(), + MacAddress = n.MacAddress.ToString(), + Hostname = n.HostName, + Latency = n.Latency.ToString(), + QueryTime = n.QueryTime.ToString(), + }) + .ToList(); + + output.Dump("NETWORK NODES LOCATED", typeNames: new TypeNamingConfig { ShowTypeNames = false }); + var global = new + { + Scanned = $"{results.NumberOfAliveNodes} UP / {results.NumberOfAddressesScanned}", + ElapsedTime = results.ElapsedTime.ToString(), + StartAddress = results.StartAddress.ToString(), + EndAddress = results.EndAddress.ToString() + + }; + + global.Dump("SCANNER RESULTS", typeNames: new TypeNamingConfig { ShowTypeNames = false }); + } + + public static void DumpInterface(this NetworkInterface adapter, UnicastIPAddressInformation ip) + { + new + { + Adapter = adapter.Name, + Description = adapter.Description, + Address = ip.Address.ToString(), + NetMask = ip.IPv4Mask.ToString() + }.Dump("ADAPTERS", typeNames: new TypeNamingConfig { ShowTypeNames = false }); + } +} \ No newline at end of file diff --git a/source/Kangaroo.CLI/Program.cs b/source/Kangaroo.CLI/Program.cs index 4416a00..7a980f8 100644 --- a/source/Kangaroo.CLI/Program.cs +++ b/source/Kangaroo.CLI/Program.cs @@ -18,6 +18,8 @@ var app = builder.Build(); -app.AddCommands(); +app.AddCommands(); +app.AddCommands(); +app.AddCommands(); app.Run(); \ No newline at end of file diff --git a/source/Kangaroo.CLI/Properties/launchSettings.json b/source/Kangaroo.CLI/Properties/launchSettings.json index d0ecd64..bd0c761 100644 --- a/source/Kangaroo.CLI/Properties/launchSettings.json +++ b/source/Kangaroo.CLI/Properties/launchSettings.json @@ -1,8 +1,16 @@ { "profiles": { - "Kangaroo.CLI": { + "WSL": { + "commandName": "WSL2", + "distributionName": "" + }, + "Kangaroo Range": { "commandName": "Project", - "commandLineArgs": "scan -s 10.0.0.1 -e 10.0.1.254 -t 50" + "commandLineArgs": "scan -s 172.26.6.100 -e 172.26.6.200 -t 50" + }, + "Kangaroo Adapter": { + "commandName": "Project", + "commandLineArgs": "adapter -a Wi-Fi" } } } \ No newline at end of file diff --git a/source/Kangaroo/Builder/Exceptions/InvalidIpRangeException.cs b/source/Kangaroo/Builder/Exceptions/InvalidIpRangeException.cs index 4a4373a..1b8e272 100644 --- a/source/Kangaroo/Builder/Exceptions/InvalidIpRangeException.cs +++ b/source/Kangaroo/Builder/Exceptions/InvalidIpRangeException.cs @@ -5,5 +5,5 @@ namespace Kangaroo; public sealed class InvalidIpRangeException : Exception { public InvalidIpRangeException(IPAddress start, IPAddress end) - : base($"{start} - {end}") { } + : base($"Invalid IP address range {start} - {end}") { } } \ No newline at end of file diff --git a/source/Kangaroo/Builder/Exceptions/InvalidNetworkAdapterException.cs b/source/Kangaroo/Builder/Exceptions/InvalidNetworkAdapterException.cs index 8c5ccf2..651d871 100644 --- a/source/Kangaroo/Builder/Exceptions/InvalidNetworkAdapterException.cs +++ b/source/Kangaroo/Builder/Exceptions/InvalidNetworkAdapterException.cs @@ -5,5 +5,5 @@ namespace Kangaroo; public sealed class InvalidNetworkAdapterException : Exception { public InvalidNetworkAdapterException(NetworkInterface @interface) - : base($"Invalid {@interface.Name}") { } + : base($"Invalid network interface {@interface.Name}") { } } \ No newline at end of file diff --git a/source/Kangaroo/Builder/Exceptions/InvalidSubnetException.cs b/source/Kangaroo/Builder/Exceptions/InvalidSubnetException.cs index f8446a1..af6c95a 100644 --- a/source/Kangaroo/Builder/Exceptions/InvalidSubnetException.cs +++ b/source/Kangaroo/Builder/Exceptions/InvalidSubnetException.cs @@ -5,5 +5,5 @@ namespace Kangaroo; public sealed class InvalidSubnetException : Exception { public InvalidSubnetException(IPAddress address, IPAddress subnet) - : base($"{address}/{subnet}") { } + : base($"Invalid IP address subnet {address}/{subnet}") { } } \ No newline at end of file diff --git a/source/Kangaroo/Builder/Exceptions/InvalidTimeoutException.cs b/source/Kangaroo/Builder/Exceptions/InvalidTimeoutException.cs index 9248e42..d6169c4 100644 --- a/source/Kangaroo/Builder/Exceptions/InvalidTimeoutException.cs +++ b/source/Kangaroo/Builder/Exceptions/InvalidTimeoutException.cs @@ -3,5 +3,5 @@ public sealed class InvalidTimeoutException : ArgumentOutOfRangeException { public InvalidTimeoutException(TimeSpan timeout) - : base($"{timeout} is out of range") { } + : base($"Invalid {timeout} is out of range") { } } \ No newline at end of file diff --git a/source/Kangaroo/Builder/Exceptions/InvalidTtlException.cs b/source/Kangaroo/Builder/Exceptions/InvalidTtlException.cs index 60cb3b7..cdc4d0a 100644 --- a/source/Kangaroo/Builder/Exceptions/InvalidTtlException.cs +++ b/source/Kangaroo/Builder/Exceptions/InvalidTtlException.cs @@ -3,5 +3,5 @@ public sealed class InvalidTtlException : ArgumentOutOfRangeException { public InvalidTtlException(int ttl) - : base($"{ttl} is out of range") { } + : base($"Invalid {ttl} is out of range") { } } \ No newline at end of file diff --git a/source/Kangaroo/Builder/Options/ScannerOptions.cs b/source/Kangaroo/Builder/Options/ScannerOptions.cs index af19d6b..5c0b849 100644 --- a/source/Kangaroo/Builder/Options/ScannerOptions.cs +++ b/source/Kangaroo/Builder/Options/ScannerOptions.cs @@ -8,6 +8,7 @@ internal sealed class ScannerOptions public IEnumerable IpAddresses { get; set; } = Enumerable.Empty(); public bool Concurrent { get; set; } = false; + public bool ScanHttpServers { get; set; } = false; public int ItemsPerBatch { get; set; } = 10; @@ -16,4 +17,9 @@ internal sealed class ScannerOptions public int TimeToLive { get; set; } = 64; public ILogger Logger { get; set; } = new DefaultLogger(); + + public Func HttpFactory { get; set; } = () => + { + return new HttpClient(); + }; } \ No newline at end of file diff --git a/source/Kangaroo/Builder/Pipeline/IScannerBuilder.cs b/source/Kangaroo/Builder/Pipeline/IScannerBuilder.cs index 44aa9c8..916e8d3 100644 --- a/source/Kangaroo/Builder/Pipeline/IScannerBuilder.cs +++ b/source/Kangaroo/Builder/Pipeline/IScannerBuilder.cs @@ -24,7 +24,7 @@ public interface IScannerRange /// IP Address to start scan from /// IP Address to stop scans at /// Next step in the pipeline - IScannerOptions WithRange(IPAddress begin, IPAddress end); + IScannerTasks WithRange(IPAddress begin, IPAddress end); /// /// Configures the scanner to use a range of IP addresses. @@ -33,7 +33,7 @@ public interface IScannerRange /// IP Address to start scan from /// IP Address to stop scans at /// Next step in the pipeline - IScannerOptions WithRange(string begin, string end); + IScannerTasks WithRange(string begin, string end); } /// @@ -49,7 +49,7 @@ public interface IScannerSubnet /// IP address "192.168.254.0" /// The subnet of the ip address Cannot be less than \16 255.255.0.0 /// Next step in the pipeline - IScannerOptions WithSubnet(IPAddress address, IPAddress subnetMask); + IScannerTasks WithSubnet(IPAddress address, IPAddress subnetMask); /// /// Configures the scanner to use the provided subnet. @@ -58,7 +58,7 @@ public interface IScannerSubnet /// IP address "192.168.254.0" /// The subnet of the ip address Cannot be less than \16 255.255.0.0 /// Next step in the pipeline - IScannerOptions WithSubnet(string address, string subnetMask); + IScannerTasks WithSubnet(string address, string subnetMask); } /// @@ -70,7 +70,7 @@ public interface IScannerInterface /// Configures the scanner to use the subnet attached to a specific adapter. /// /// Next step in the pipeline - IScannerOptions WithInterface(NetworkInterface? @interface = null); + IScannerTasks WithInterface(NetworkInterface? @interface = null); } /// @@ -82,13 +82,20 @@ public interface IScannerSpecific /// Configures the scanner to use the provided IP addresses. /// /// Next step in the pipeline - IScannerOptions WithAddresses(IEnumerable addresses); + IScannerTasks WithAddresses(IEnumerable addresses); } #endregion #region STEP 2 OPTION CONFIGURATION +public interface IScannerTasks : IScannerWebServer, IScannerOptions { } + +public interface IScannerWebServer +{ + IScannerOptions WithHttpScan(Func? httpClientFactory = null); +} + /// /// Optional steps /// diff --git a/source/Kangaroo/Builder/Pipeline/ScannerBuilder.cs b/source/Kangaroo/Builder/Pipeline/ScannerBuilder.cs index 0ba64ff..802afb5 100644 --- a/source/Kangaroo/Builder/Pipeline/ScannerBuilder.cs +++ b/source/Kangaroo/Builder/Pipeline/ScannerBuilder.cs @@ -10,7 +10,7 @@ namespace Kangaroo; /// The scanner builder creates scanners by walking the users through the build pipeline. /// This is the entry point for the kangaroo scanner /// -public sealed class ScannerBuilder : IScannerIpConfiguration, IScannerOptions, IScannerTimeoutNext, IScannerTtlNext, IScannerParallelNext +public sealed class ScannerBuilder : IScannerIpConfiguration, IScannerTasks, IScannerOptions, IScannerTimeoutNext, IScannerTtlNext, IScannerParallelNext { /// /// Starts the scanner configuration process. @@ -24,42 +24,42 @@ public static IScannerIpConfiguration Configure() private readonly ScannerOptions _options = new(); /// - public IScannerOptions WithSubnet(IPAddress address, IPAddress subnetMask) + public IScannerTasks WithSubnet(IPAddress address, IPAddress subnetMask) { _options.IpAddresses = AddressFactory.CreateAddressesFromSubnet(address, subnetMask); return this; } /// - public IScannerOptions WithSubnet(string address, string subnetMask) + public IScannerTasks WithSubnet(string address, string subnetMask) { _options.IpAddresses = AddressFactory.CreateAddressesFromSubnet(IPAddress.Parse(address), IPAddress.Parse(subnetMask)); return this; } /// - public IScannerOptions WithRange(IPAddress begin, IPAddress end) + public IScannerTasks WithRange(IPAddress begin, IPAddress end) { _options.IpAddresses = AddressFactory.CreateAddressesFromRange(begin, end); return this; } /// - public IScannerOptions WithRange(string begin, string end) + public IScannerTasks WithRange(string begin, string end) { _options.IpAddresses = AddressFactory.CreateAddressesFromRange(IPAddress.Parse(begin), IPAddress.Parse(end)); return this; } /// - public IScannerOptions WithAddresses(IEnumerable addresses) + public IScannerTasks WithAddresses(IEnumerable addresses) { _options.IpAddresses = addresses; return this; } /// - public IScannerOptions WithInterface(NetworkInterface? @interface = null) + public IScannerTasks WithInterface(NetworkInterface? @interface = null) { _options.IpAddresses = @interface != null ? AddressFactory.CreateAddressesFromInterface(@interface) @@ -68,6 +68,18 @@ public IScannerOptions WithInterface(NetworkInterface? @interface = null) return this; } + public IScannerOptions WithHttpScan(Func? httpClientFactory = null) + { + _options.ScanHttpServers = true; + + if (httpClientFactory != null) + { + _options.HttpFactory = httpClientFactory; + } + + return this; + } + /// public IScannerTimeoutNext WithMaxTimeout(TimeSpan timeout) { diff --git a/source/Kangaroo/Kangaroo.csproj b/source/Kangaroo/Kangaroo.csproj index 7fc82d4..059c08b 100644 --- a/source/Kangaroo/Kangaroo.csproj +++ b/source/Kangaroo/Kangaroo.csproj @@ -8,7 +8,7 @@ True Kangaroo network scanner - 0.0.2 + 0.0.3 The kangaroo scanner is a network scanner designed to operate within a C# dotnet application. The kangaroo scanner allows you to query network endpoints and operate common tasks against them. https://github.com/ewilliams0305/kangaroo kangaroo-logo.png diff --git a/source/Kangaroo/Model/NetworkNode.cs b/source/Kangaroo/Model/NetworkNode.cs index f27ae39..508367f 100644 --- a/source/Kangaroo/Model/NetworkNode.cs +++ b/source/Kangaroo/Model/NetworkNode.cs @@ -16,11 +16,12 @@ public record NetworkNode( IPAddress IpAddress, MacAddress MacAddress, string? HostName, + string? WebServer, TimeSpan? Latency, TimeSpan QueryTime, bool Alive) { - internal static NetworkNode BadNode(IPAddress ipAddress, TimeSpan elapsedTime) => new(ipAddress, MacAddress.Empty, null, null, elapsedTime, false); + internal static NetworkNode BadNode(IPAddress ipAddress, TimeSpan elapsedTime) => new(ipAddress, MacAddress.Empty, null, null, null, elapsedTime, false); /// public override string ToString() diff --git a/source/Kangaroo/Queries/IQueryWebServer.cs b/source/Kangaroo/Queries/IQueryWebServer.cs new file mode 100644 index 0000000..23daaf9 --- /dev/null +++ b/source/Kangaroo/Queries/IQueryWebServer.cs @@ -0,0 +1,8 @@ +using System.Net; + +namespace Kangaroo.Queries; + +internal interface IQueryWebServer : IDisposable +{ + Task Query(IPAddress ipAddress, CancellationToken token = default); +} \ No newline at end of file diff --git a/source/Kangaroo/Queries/QueryHostname.cs b/source/Kangaroo/Queries/QueryHostname.cs index 576734a..2c4fd53 100644 --- a/source/Kangaroo/Queries/QueryHostname.cs +++ b/source/Kangaroo/Queries/QueryHostname.cs @@ -1,6 +1,6 @@ -using System.Net; +using Microsoft.Extensions.Logging; +using System.Net; using System.Net.Sockets; -using Microsoft.Extensions.Logging; namespace Kangaroo.Queries; @@ -8,11 +8,10 @@ internal sealed class QueryHostname : IQueryHostname { private readonly ILogger _logger; - public QueryHostname(ILogger logger) + internal QueryHostname(ILogger logger) { _logger = logger; } - #region Implementation of IQueryHostname /// public async Task Query(IPAddress ipAddress, CancellationToken token = default) @@ -41,6 +40,4 @@ public QueryHostname(ILogger logger) return null; } - - #endregion } \ No newline at end of file diff --git a/source/Kangaroo/Queries/QueryNetworkNode.cs b/source/Kangaroo/Queries/QueryNetworkNode.cs index 0876692..8b84e37 100644 --- a/source/Kangaroo/Queries/QueryNetworkNode.cs +++ b/source/Kangaroo/Queries/QueryNetworkNode.cs @@ -11,13 +11,15 @@ internal sealed class QueryNetworkNode: IQueryNetworkNode private readonly IQueryPingResults _ping; private readonly IQueryMacAddress _mac; private readonly IQueryHostname _host; + private readonly IQueryWebServer? _http; - public QueryNetworkNode(ILogger logger, IQueryPingResults ping, IQueryMacAddress mac, IQueryHostname host) + public QueryNetworkNode(ILogger logger, IQueryPingResults ping, IQueryMacAddress mac, IQueryHostname host, IQueryWebServer? http = null) { _logger = logger; _ping = ping; _mac = mac; _host = host; + _http = http; } /// @@ -41,11 +43,16 @@ public async Task Query(IPAddress ipAddress, CancellationToken toke var mac = await _mac.Query(ipAddress, token); var host = await _host.Query(ipAddress, token); + var server = _http != null + ? await _http.Query(ipAddress, token) + : "N/A"; + stopwatch.Stop(); var node = new NetworkNode( ipAddress, mac, host != null ? host.HostName : "N/A", + server, TimeSpan.FromMilliseconds(reply.RoundtripTime), stopwatch.Elapsed, true); @@ -66,6 +73,7 @@ public async Task Query(IPAddress ipAddress, CancellationToken toke public void Dispose() { _ping.Dispose(); + _http?.Dispose(); } #endregion diff --git a/source/Kangaroo/Queries/QueryWebServer.cs b/source/Kangaroo/Queries/QueryWebServer.cs new file mode 100644 index 0000000..a79b096 --- /dev/null +++ b/source/Kangaroo/Queries/QueryWebServer.cs @@ -0,0 +1,39 @@ +using System.Net; + +namespace Kangaroo.Queries; + +internal sealed class QueryWebServer: IQueryWebServer +{ + private readonly HttpClient _client; + + public QueryWebServer(HttpClient? client = null) + { + _client = client ?? new HttpClient(); + } + + /// + public async Task Query(IPAddress ipAddress, CancellationToken token = default) + { + try + { + _client.BaseAddress = new Uri($"http://{ipAddress}"); + _client.Timeout = TimeSpan.FromMilliseconds(500); + + var response = await _client.GetAsync("/", token); + return response.Headers.Server.ToString(); + } + catch (Exception e) + { + Console.WriteLine(e); + return string.Empty; + } + + } + + /// + public void Dispose() + { + _client.Dispose(); + } + +} \ No newline at end of file