From d8e7fed3035da6e5bab6068ab009f770b8f6a2af Mon Sep 17 00:00:00 2001 From: Matthew Carney Date: Sat, 21 Oct 2023 12:02:29 +0100 Subject: [PATCH] .NET 6 warning fixing Removed update checker code --- src/Commands/Listen.cs | 52 +++++++++------ src/Commands/Lookup.cs | 46 +++++++++++-- src/Commands/Scan.cs | 18 +++-- src/Display/ConsoleDisplay.cs | 25 +++++-- src/Display/ConsoleMessageHandler.cs | 32 ++++----- src/File/LogMessageHandler.cs | 2 +- src/Network/ICMP.cs | 9 +++ src/Network/IPv4.cs | 11 +++- src/Network/Ping.cs | 99 +++++++++++++++++++--------- src/Program.cs | 18 +++-- src/Structures/PingAttributes.cs | 57 ++++++++++------ src/Structures/PingReply.cs | 2 +- src/Structures/PingResults.cs | 10 ++- src/Utils/CommandLine.cs | 1 - src/Utils/Helper.cs | 62 ++--------------- 15 files changed, 273 insertions(+), 171 deletions(-) diff --git a/src/Commands/Listen.cs b/src/Commands/Listen.cs index 39ccad1..ebea285 100644 --- a/src/Commands/Listen.cs +++ b/src/Commands/Listen.cs @@ -23,32 +23,41 @@ internal static class Listen public static void Start(CancellationToken cancellationToken, string address = "") { - IPAddress[] addresses = new IPAddress[0]; + if (System.Environment.OSVersion.Platform != PlatformID.Win32NT) + { + Helper.ErrorAndExit("Listen mode is not supported on a non windows platform."); + return; + } + // Look up local addresses to listen on + IPAddress[]? localAddresses; if (address == "") { // If no address is given then listen on all local addresses - addresses = GetLocalAddresses(); - if (addresses == null) - { - return; - } + localAddresses = GetLocalAddresses(); + } else { // Otherwise just listen on the address we are given - addresses = new IPAddress[] { IPAddress.Parse(address) }; + localAddresses = new IPAddress[] { IPAddress.Parse(address) }; + } + + if (localAddresses == null) + { + Helper.ErrorAndExit("Could not find local addresses to listen on."); + return; } // Start a listening thread for each ipv4 local address - int size = addresses.Length; + int size = localAddresses.Length; _listenThreads = new Thread[size]; - for (int x = 0; x < addresses.Length; x++) + for (int x = 0; x < localAddresses.Length; x++) { int index = x; - _listenThreads[index] = new Thread(() => + _listenThreads[index] = new(() => { - ListenForICMPOnAddress(addresses[index]); + ListenForICMPOnAddress(localAddresses[index]); }); _listenThreads[index].IsBackground = true; _listenThreads[index].Start(); @@ -68,9 +77,9 @@ public static void Start(CancellationToken cancellationToken, string address = " //Display.ListenResults(results); } - private static IPAddress[] GetLocalAddresses() + private static IPAddress[]? GetLocalAddresses() { - IPHostEntry hostAddress = null; + IPHostEntry hostAddress; // Get all addresses assocatied with this computer try @@ -80,10 +89,11 @@ private static IPAddress[] GetLocalAddresses() catch (Exception e) { ConsoleDisplay.Error($"Could not fetch local addresses ({e.GetType().ToString().Split('.').Last()})"); + return null; } // Only get IPv4 address - List addresses = new List(); + List addresses = new(); foreach (IPAddress address in hostAddress.AddressList) { if (address.AddressFamily == AddressFamily.InterNetwork) @@ -97,8 +107,8 @@ private static IPAddress[] GetLocalAddresses() public static void ListenForICMPOnAddress(IPAddress address) { - Socket listeningSocket = null; - PingResults results = new PingResults(); + Socket listeningSocket; + PingResults results = new(); int bufferSize = 4096; // Create listener socket @@ -106,7 +116,9 @@ public static void ListenForICMPOnAddress(IPAddress address) { listeningSocket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp); listeningSocket.Bind(new IPEndPoint(address, 0)); +#pragma warning disable CA1416 // Validate platform compatibility - We shouldn't be running listen mode on non windows platform listeningSocket.IOControl(IOControlCode.ReceiveAll, new byte[] { 1, 0, 0, 0 }, new byte[] { 1, 0, 0, 0 }); // Set SIO_RCVALL flag to socket IO control +#pragma warning restore CA1416 // Validate platform compatibility listeningSocket.ReceiveBufferSize = bufferSize; } catch (Exception e) @@ -127,10 +139,11 @@ public static void ListenForICMPOnAddress(IPAddress address) // Recieve any incoming ICMPv4 packets EndPoint remoteEndPoint = new IPEndPoint(IPAddress.Any, 0); int bytesRead = listeningSocket.ReceiveFrom(buffer, ref remoteEndPoint); - ICMP response = new ICMP(buffer, bytesRead); + ICMP response = new(buffer, bytesRead); + string remoteEndPointIp = remoteEndPoint.ToString() ?? string.Empty; // Display captured packet - ConsoleDisplay.CapturedPacket(address.ToString(), response, remoteEndPoint.ToString(), DateTime.Now.ToString("h:mm:ss.ff tt"), bytesRead); + ConsoleDisplay.CapturedPacket(address.ToString(), response, remoteEndPointIp, DateTime.Now.ToString("h:mm:ss.ff tt"), bytesRead); // Store results results.CountPacketType(response.Type); @@ -145,7 +158,8 @@ public static void ListenForICMPOnAddress(IPAddress address) } } - listeningSocket.Close(); + // No nice way to cancel from listening and close socket. Just to got to hope/assume runtime does it when the thread is killed. + //listeningSocket.Close(); } } } \ No newline at end of file diff --git a/src/Commands/Lookup.cs b/src/Commands/Lookup.cs index 43cd709..07741ca 100644 --- a/src/Commands/Lookup.cs +++ b/src/Commands/Lookup.cs @@ -7,7 +7,9 @@ using System.Net; using System.Net.NetworkInformation; using System.Net.Sockets; +using System.Reflection; using System.Text; +using System.Text.Json; using System.Xml; namespace PowerPing @@ -57,6 +59,39 @@ public static string GetLocalAddress() /// Display detailed or simplified location info public static string GetAddressLocationInfo(string addr, bool detailed) { + //using (HttpClient webClient = new()) + //{ + // try + // { + // string jsonResult = string.Empty; + // webClient.DefaultRequestHeaders.Add("User-Agent", "PowerPing (version_check)"); + // webClient.BaseAddress = new Uri(@"http://api.github.com/repos/killeroo/powerping/releases/latest"); + // webClient.GetStringAsync(jsonResult).GetAwaiter().GetResult(); + + // Dictionary? jsonTable = JsonSerializer.Deserialize>(jsonResult); + + // // Extract version from returned json + // if (jsonTable.ContainsKey("tag_name")) + // { + // string matchString = jsonTable["tag_name"]; + // Version theirVersion = new(matchString.Split(':')[1].Replace("\"", string.Empty).Replace("v", string.Empty)); + // Version? ourVersion = Assembly.GetExecutingAssembly().GetName().Version; + + // if (theirVersion > ourVersion) + // { + // Console.WriteLine(); + // Console.WriteLine("========================================================="); + // Console.WriteLine("A new version of PowerPing is available ({0})", theirVersion); + // Console.WriteLine("Download the new version at: {0}", @"https://github.com/killeroo/powerping/releases/latest"); + // Console.WriteLine("========================================================="); + // Console.WriteLine(); + // } + // } + // } + // catch (Exception) { } // We just want to blanket catch any exception and silently continue + //} + + string result = ""; try @@ -70,7 +105,7 @@ public static string GetAddressLocationInfo(string addr, bool detailed) $"http://api.ipstack.com/{addr}?access_key={key}&output=xml"); // Load xml file into object - XmlDocument xmlDoc = new XmlDocument(); + XmlDocument xmlDoc = new(); xmlDoc.LoadXml(downloadedText); XmlNodeList elements = (xmlDoc.DocumentElement).ChildNodes; @@ -121,7 +156,7 @@ public static string GetAddressLocationInfo(string addr, bool detailed) /// public static string QueryDNS(string address, AddressFamily af) { - IPAddress ipAddr = null; + IPAddress? ipAddr; // Check address format if (Uri.CheckHostName(address) == UriHostNameType.Unknown) @@ -154,9 +189,12 @@ public static string QueryDNS(string address, AddressFamily af) if (ipAddr == null) { Helper.ErrorAndExit("PowerPing could not find host [" + address + "] " + Environment.NewLine + "Check address and try again."); + return string.Empty; + } + else + { + return ipAddr.ToString(); } - - return ipAddr.ToString(); } /// diff --git a/src/Commands/Scan.cs b/src/Commands/Scan.cs index ce47cde..29ccbdd 100644 --- a/src/Commands/Scan.cs +++ b/src/Commands/Scan.cs @@ -34,23 +34,29 @@ public class HostInformation public string Address { get; set; } public string HostName { get; set; } public double ResponseTime { get; set; } + + public HostInformation() + { + Address = string.Empty; + HostName = string.Empty; + } } private static volatile bool _cancelled = false; public static void Start(string range, CancellationToken cancellationToken) { - List addresses = new List(); - List activeHosts = new List(); - Stopwatch timer = new Stopwatch(); + List addresses = new(); + List activeHosts = new(); + Stopwatch timer = new(); // Get addresses to scan from range addresses = ParseRange(range); // Setup addresses and threads - var splitAddresses = Helper.PartitionList(addresses, THREAD_COUNT); + List[] splitAddresses = Helper.PartitionList(addresses, THREAD_COUNT); Thread[] threads = new Thread[THREAD_COUNT]; - object lockObject = new object(); + object lockObject = new(); int scanned = 0; // Run the threads @@ -72,7 +78,7 @@ public static void Start(string range, CancellationToken cancellationToken) // Send ping PingResults results = ping.Send(host); - if (results.ScanWasCanceled) { + if (results.ScanWasCancelled) { // Cancel was requested during scan throw new OperationCanceledException(); } diff --git a/src/Display/ConsoleDisplay.cs b/src/Display/ConsoleDisplay.cs index 2539189..614b58e 100644 --- a/src/Display/ConsoleDisplay.cs +++ b/src/Display/ConsoleDisplay.cs @@ -16,7 +16,7 @@ namespace PowerPing /// internal class ConsoleDisplay { - public static DisplayConfiguration? Configuration { get; set; } + public static DisplayConfiguration Configuration { get; set; } = new DisplayConfiguration(); public static CancellationToken CancellationToken { get; set; } // Stores console cursor position, used for updating text at position @@ -133,7 +133,7 @@ public static void SetAsciiReplySymbolsTheme(int theme) public static void Version() { string assemblyVersion = Helper.GetVersionString(); - string assemblyName = Assembly.GetExecutingAssembly().GetName().Name; + string assemblyName = Assembly.GetExecutingAssembly().GetName().Name ?? string.Empty; Console.WriteLine(assemblyName + " " + assemblyVersion); } @@ -146,8 +146,6 @@ public static void Help() // Print help message Console.WriteLine(Assembly.GetExecutingAssembly().GetName().Name + " " + Helper.GetVersionString()); Console.WriteLine(ProgramStrings.HELP_MSG); - - Helper.CheckRecentVersion(); } /// @@ -696,7 +694,7 @@ public static void Timeout(int seq) /// Display error message /// /// Error message to display - public static void Error(string errMsg, Exception e = null) + public static void Error(string errMsg, Exception e) { Console.ForegroundColor = ConsoleColor.Yellow; string errorText = (e != null ? $"{errMsg} ({e.GetType().Name})" : errMsg); @@ -708,7 +706,22 @@ public static void Error(string errMsg, Exception e = null) ResetColor(); } - public static void Fatal(string errMsg, Exception e = null) + /// + /// Display error message + /// + /// Error message to display + public static void Error(string errMsg) + { + Console.ForegroundColor = ConsoleColor.Yellow; + + // Write error message + Console.WriteLine(errMsg); + + // Reset console colours + ResetColor(); + } + + public static void Fatal(string errMsg, Exception e) { Console.ForegroundColor = ConsoleColor.Red; string errorText = (e != null ? $"{errMsg} ({e.GetType().Name})" : errMsg); diff --git a/src/Display/ConsoleMessageHandler.cs b/src/Display/ConsoleMessageHandler.cs index f2c022c..abde0df 100644 --- a/src/Display/ConsoleMessageHandler.cs +++ b/src/Display/ConsoleMessageHandler.cs @@ -2,13 +2,14 @@ { public class ConsoleMessageHandler { - public DisplayConfiguration DisplayConfig = new DisplayConfiguration(); - public PingAttributes Attributes = new PingAttributes(); - public CancellationToken Token = new CancellationToken(); + public DisplayConfiguration DisplayConfig = new(); + public PingAttributes Attributes = new(); + public CancellationToken Token = new(); public ConsoleMessageHandler(DisplayConfiguration config, CancellationToken token) { - DisplayConfig = config; + Attributes = new(); + DisplayConfig = config ?? new DisplayConfiguration(); Token = token; } @@ -17,9 +18,6 @@ public void OnError(PingError error) if (error.Fatal) { ConsoleDisplay.Fatal(error.Message, error.Exception); - - // Exit on fatal error - Helper.ExitWithError(); } else { @@ -36,19 +34,23 @@ public void OnReply(PingReply response) { // Determine what form the response address is going to be displayed in // TODO: Move this when lookup refactor is done - string responseAddress = response.Endpoint.ToString(); - if (DisplayConfig.UseResolvedAddress) + string responseAddress = response.EndpointAddress; + if (responseAddress == string.Empty || DisplayConfig.UseInputtedAddress) + { + if (Attributes != null && Attributes.InputtedAddress != null) + { + responseAddress = Attributes.InputtedAddress; + } + } + else if (DisplayConfig.UseResolvedAddress) { + // Returned address normally have port at the end (eg 8.8.8.8:0) so we need to remove that before trying to query the DNS - string responseIP = responseAddress.ToString().Split(':')[0]; + string responseIP = responseAddress.Split(':')[0]; // Resolve the ip and store as the response address responseAddress = Helper.RunWithCancellationToken(() => Lookup.QueryHost(responseIP), Token); } - else if (DisplayConfig.UseInputtedAddress) - { - responseAddress = Attributes.InputtedAddress; - } ConsoleDisplay.ReplyPacket( response.Packet, @@ -57,7 +59,7 @@ public void OnReply(PingReply response) response.RoundTripTime, response.BytesRead); - if (Attributes.BeepMode == 2) + if (Attributes != null && Attributes.BeepMode == 2) { try { Console.Beep(); } catch (Exception) { } // Silently continue if Console.Beep errors diff --git a/src/File/LogMessageHandler.cs b/src/File/LogMessageHandler.cs index b50526c..f675eb6 100644 --- a/src/File/LogMessageHandler.cs +++ b/src/File/LogMessageHandler.cs @@ -106,7 +106,7 @@ internal void OnReply(PingReply reply) _logFile.Append($"[{_destinationAddress}] " + $"[{reply.Timestamp.ToString(DATETIME_STRING_FORMAT)}] " + $"[REPLY] " + - $"endpoint={reply.Endpoint.ToString()} " + + $"endpoint={reply.EndpointAddress} " + $"seq={reply.SequenceNumber} " + $"bytes={reply.BytesRead} " + $"type={reply.Packet.Type} " + diff --git a/src/Network/ICMP.cs b/src/Network/ICMP.cs index b741bd8..b8bede6 100644 --- a/src/Network/ICMP.cs +++ b/src/Network/ICMP.cs @@ -11,6 +11,15 @@ namespace PowerPing /// public class ICMP { + public static readonly ICMP EmptyPacket = new() + { + Type = 0, + Code = 0, + Checksum = 0, + MessageSize = 0, + Message = new byte[1024], + }; + // Packet attributes public byte Type; public byte Code; diff --git a/src/Network/IPv4.cs b/src/Network/IPv4.cs index c028930..3907bbf 100644 --- a/src/Network/IPv4.cs +++ b/src/Network/IPv4.cs @@ -25,7 +25,12 @@ internal class IPv4 public byte[] Data; // Constructors - public IPv4() { } + public IPv4() + { + Source = IPAddress.Any; + Destination = IPAddress.Any; + Data = new byte[4]; + } public IPv4(byte[] data, int size) { @@ -64,7 +69,9 @@ public IPv4(byte[] data, int size) public byte[] GetBytes() { - byte[] payload = new byte[HeaderLength + Data.Length]; + int dataLength = Data != null ? Data.Length : 0; + + byte[] payload = new byte[HeaderLength + dataLength]; Buffer.BlockCopy(BitConverter.GetBytes((byte)(Version << 4) | HeaderLength), 0, payload, 0, 1); // TODO: divide length by 4, Shift 4 bits to right, OR (basically copy) the other 4 bits into where the version was Buffer.BlockCopy(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(TypeOfService)), 0, payload, 1, 1); Buffer.BlockCopy(BitConverter.GetBytes(IPAddress.HostToNetworkOrder(TotalLength)), 0, payload, 2, 2); diff --git a/src/Network/Ping.cs b/src/Network/Ping.cs index 394d795..0f05267 100644 --- a/src/Network/Ping.cs +++ b/src/Network/Ping.cs @@ -24,13 +24,13 @@ internal class Ping public Action? OnFinish = null; public Action? OnError = null; - private PingAttributes _attributes = null; - private PingResults _results = null; + private PingAttributes _attributes = new(); + private PingResults _results = new(); - private Socket _socket = null; - private ICMP _packet = null; + private Socket? _socket = null; + private ICMP? _packet = null; private int _packetSize = 0; - private IPEndPoint _remoteEndpoint = null; + private IPEndPoint? _remoteEndpoint = null; private readonly CancellationToken _cancellationToken; private bool _debugIpHeader = false; @@ -51,7 +51,6 @@ public Ping( CancellationToken cancellationToken) { _attributes = attributes; - _results = new PingResults(); _cancellationToken = cancellationToken; Setup(); @@ -114,10 +113,10 @@ private void Setup() private void Cleanup() { // On deconstruction - _socket.Close(); + _socket?.Close(); _packet = null; - _attributes = null; - _results = null; + _attributes.ResetToDefaultValues(); + _results.Reset(); OnResultsUpdate = null; } @@ -164,6 +163,9 @@ private void CreateRawSocket() _errorMesssage.Fatal = true; OnError.Invoke(_errorMesssage); + + // Exit on fatal error + Helper.ExitWithError(); } } @@ -171,6 +173,11 @@ private void CreateRawSocket() private void SetupSocketOptions() { + if (_socket == null) + { + return; + } + _socket.Ttl = (short)_attributes.Ttl; _socket.DontFragment = _attributes.DontFragment; _socket.ReceiveBufferSize = _attributes.ReceiveBufferSize; @@ -197,6 +204,11 @@ private void CreateRemoteEndpoint() private void SetSocketReceiveTimeout(int timeout) { + if (_socket == null) + { + return; + } + if (timeout != _currentReceiveTimeout) { _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, timeout); @@ -227,12 +239,22 @@ private void ConstructPacket() private void UpdatePacketSequenceNumber(int sequence) { + if (_packet == null) + { + return; + } + _currentSequenceNumber = (ushort)sequence; Buffer.BlockCopy(BitConverter.GetBytes(_currentSequenceNumber), 0, _packet.Message, 2, 2); } private void UpdatePacketMessage(byte[] message) { + if (_packet == null) + { + return; + } + // Copy into packet // (NOTE: the offset is where the sequence number and packet identier are stored) Buffer.BlockCopy(message, 0, _packet.Message, 4, message.Length); @@ -247,6 +269,11 @@ private void UpdatePacketMessage(byte[] message) private void UpdatePacketChecksum() { + if (_packet == null) + { + return; + } + _packet.Checksum = 0; UInt16 chksm = _packet.GetChecksum(); _packet.Checksum = chksm; @@ -254,6 +281,11 @@ private void UpdatePacketChecksum() private void SendPacket() { + if (_remoteEndpoint == null || _socket == null || _packet == null) + { + return; + } + byte[] receiveBuffer = new byte[_attributes.ReceiveBufferSize]; // Ipv4Header.length + IcmpHeader.length + attrs.recievebuffersize int bytesRead = 0; @@ -320,7 +352,7 @@ private void SendPacket() } // Try and recieve a packet - ICMP response = null; + ICMP response = ICMP.EmptyPacket; EndPoint responseEP = _remoteEndpoint; TimeSpan replyTime = TimeSpan.Zero; ReceivePacket(ref response, ref responseEP, ref replyTime, ref bytesRead, requestTimestamp); @@ -361,7 +393,7 @@ private void SendPacket() } catch (OperationCanceledException) { - _results.ScanWasCanceled = true; + _results.ScanWasCancelled = true; break; } catch (Exception e) @@ -390,6 +422,11 @@ private void SendPacket() private void ReceivePacket(ref ICMP response, ref EndPoint responseEndPoint, ref TimeSpan replyTime, ref int bytesRead, long requestTimestamp) { + if (_socket == null || _packet == null) + { + return; + } + byte[] receiveBuffer = new byte[_attributes.ReceiveBufferSize]; // Wait for request @@ -419,11 +456,7 @@ private void ReceivePacket(ref ICMP response, ref EndPoint responseEndPoint, ref } replyTime = new TimeSpan(Helper.StopwatchToTimeSpanTicks(Stopwatch.GetTimestamp() - requestTimestamp)); - if (bytesRead == 0) - { - response = null; - } - else + if (bytesRead != 0) { // Store reply packet response = new ICMP(receiveBuffer, bytesRead); @@ -431,18 +464,22 @@ private void ReceivePacket(ref ICMP response, ref EndPoint responseEndPoint, ref if (_debugIpHeader) { // Print out parsed IPv4 header data - IPv4 header = new IPv4(receiveBuffer, bytesRead); - ICMP ping = new ICMP(header.Data, header.TotalLength - header.HeaderLength, 0); - header.GetBytes(); - Console.BackgroundColor = ConsoleColor.Red; - Console.ForegroundColor = ConsoleColor.Black; - Console.WriteLine(header.PrettyPrint()); - Console.ResetColor(); - - Console.BackgroundColor = ConsoleColor.Yellow; - Console.ForegroundColor = ConsoleColor.Black; - Console.WriteLine(ping.PrettyPrint()); - Console.ResetColor(); + IPv4 header = new(receiveBuffer, bytesRead); + if (header.Data != null) + { + ICMP ping = new(header.Data, header.TotalLength - header.HeaderLength, 0); + + header.GetBytes(); + Console.BackgroundColor = ConsoleColor.Red; + Console.ForegroundColor = ConsoleColor.Black; + Console.WriteLine(header.PrettyPrint()); + Console.ResetColor(); + + Console.BackgroundColor = ConsoleColor.Yellow; + Console.ForegroundColor = ConsoleColor.Black; + Console.WriteLine(ping.PrettyPrint()); + Console.ResetColor(); + } } // If we sent an echo and receive a response with a different identifier or sequence @@ -453,17 +490,17 @@ private void ReceivePacket(ref ICMP response, ref EndPoint responseEndPoint, ref ushort responseSequenceNum = BitConverter.ToUInt16(response.Message, 2); if (responseSessionId != _sessionId || responseSequenceNum != _currentSequenceNumber) { - response = null; + response = ICMP.EmptyPacket; } } } - } while (response == null); + } while (response == ICMP.EmptyPacket); // Raise message on response if (OnReply != null) { _responseMessage.Packet = response; - _responseMessage.Endpoint = responseEndPoint as IPEndPoint; + _responseMessage.EndpointAddress = responseEndPoint.ToString() ?? string.Empty; _responseMessage.Timestamp = DateTime.Now; _responseMessage.SequenceNumber = _currentSequenceNumber; _responseMessage.BytesRead = bytesRead; diff --git a/src/Program.cs b/src/Program.cs index 636f720..f455e76 100644 --- a/src/Program.cs +++ b/src/Program.cs @@ -10,8 +10,8 @@ internal static class Program { private static readonly CancellationTokenSource _cancellationTokenSource = new (); private static DisplayConfiguration _displayConfiguration = new (); - private static LogMessageHandler _logMessageHandler = null; - private static ConsoleMessageHandler _consoleMessageHandler = null; + private static LogMessageHandler? _logMessageHandler = null; + private static ConsoleMessageHandler? _consoleMessageHandler = null; /// /// Main entry point of PowerPing @@ -65,12 +65,11 @@ private static void Main(string[] args) ConsoleDisplay.Configuration = _displayConfiguration; ConsoleDisplay.CancellationToken = _cancellationTokenSource.Token; - // Add handler to display ping events - _consoleMessageHandler = new ConsoleMessageHandler(_displayConfiguration, _cancellationTokenSource.Token); // Select correct function using opMode switch (parsedAttributes.Operation) { +#pragma warning disable CS8604 // InputtedAddress has to be equal to something so disable null reference warning for this. case PingOperation.Listen: RunListenOperation(args, parsedAttributes); break; case PingOperation.Location: RunLocationOperation(parsedAttributes.InputtedAddress); break; case PingOperation.Whoami: RunWhoAmIOperation(); break; @@ -79,6 +78,7 @@ private static void Main(string[] args) case PingOperation.Flood: RunFloodOperation(parsedAttributes.InputtedAddress, _cancellationTokenSource.Token); break; case PingOperation.Scan: RunScanOperation(parsedAttributes.InputtedAddress, _cancellationTokenSource.Token); break; case PingOperation.Normal: RunNormalPingOperation(parsedAttributes, _cancellationTokenSource.Token); break; +#pragma warning restore CS8604 // Possible null reference argument. default: Helper.ErrorAndExit("Could not determine ping operation"); @@ -96,7 +96,7 @@ private static void Main(string[] args) /// /// /// - private static void ExitHandler(object sender, ConsoleCancelEventArgs args) + private static void ExitHandler(object? sender, ConsoleCancelEventArgs args) { // Cancel termination args.Cancel = true; @@ -115,6 +115,11 @@ private static void RunNormalPingOperation( PingAttributes attributes, CancellationToken cancellationToken) { + if (attributes == null) + { + return; + } + Ping p = new Ping(attributes, cancellationToken); if (attributes.EnableLogging) @@ -135,6 +140,9 @@ private static void RunNormalPingOperation( p.OnError += _logMessageHandler.OnError; } + // Add handler to display ping events + _consoleMessageHandler = new ConsoleMessageHandler(_displayConfiguration, _cancellationTokenSource.Token); + // Add callbacks for console display p.OnStart += _consoleMessageHandler.OnStart; p.OnFinish += _consoleMessageHandler.OnFinish; diff --git a/src/Structures/PingAttributes.cs b/src/Structures/PingAttributes.cs index 718cbb5..5b74258 100644 --- a/src/Structures/PingAttributes.cs +++ b/src/Structures/PingAttributes.cs @@ -52,35 +52,23 @@ public class PingAttributes public PingAttributes() { - // Default properties - InputtedAddress = ""; - ResolvedAddress = ""; + // Analyser complains about these not being null even though they are set in ResetToDefaultValues (sigh...) + InputtedAddress = string.Empty; + ResolvedAddress = string.Empty; + SourceAddress = string.Empty; + LogFilePath = string.Empty; Message = Helper.RandomString(26); - Interval = 1000; - Timeout = 3000; - Count = 5; - Ttl = 255; - Type = 0x08; - Code = 0x00; - ArtificalMessageSize = -1; - BeepMode = 0; - ReceiveBufferSize = 5096; - // Default options - Continous = false; - UseICMPv4 = true; - UseICMPv6 = false; - RandomMessage = false; - DontFragment = false; - RandomTiming = false; - Operation = PingOperation.Normal; + ResetToDefaultValues(); } public PingAttributes(PingAttributes attributes) { InputtedAddress = attributes.InputtedAddress; ResolvedAddress = attributes.ResolvedAddress; + SourceAddress = attributes.SourceAddress; Message = attributes.Message; + LogFilePath = attributes.LogFilePath; Interval = attributes.Interval; Timeout = attributes.Timeout; Count = attributes.Count; @@ -99,6 +87,35 @@ public PingAttributes(PingAttributes attributes) RandomTiming = attributes.RandomTiming; Operation = attributes.Operation; } + + public void ResetToDefaultValues() + { + // Default properties + InputtedAddress = string.Empty; + ResolvedAddress = string.Empty; + SourceAddress = string.Empty; + LogFilePath = string.Empty; + Message = Helper.RandomString(26); + Interval = 1000; + Timeout = 3000; + Count = 5; + Ttl = 255; + Type = 0x08; + Code = 0x00; + ArtificalMessageSize = -1; + BeepMode = 0; + ReceiveBufferSize = 5096; + + // Default options + Continous = false; + UseICMPv4 = true; + UseICMPv6 = false; + RandomMessage = false; + DontFragment = false; + RandomTiming = false; + Operation = PingOperation.Normal; + LogFilePath = string.Empty; + } } } \ No newline at end of file diff --git a/src/Structures/PingReply.cs b/src/Structures/PingReply.cs index 5b98d79..5334961 100644 --- a/src/Structures/PingReply.cs +++ b/src/Structures/PingReply.cs @@ -12,7 +12,7 @@ namespace PowerPing public struct PingReply { public ICMP Packet; - public IPEndPoint Endpoint; + public string EndpointAddress; public DateTime Timestamp; public int SequenceNumber; public TimeSpan RoundTripTime; diff --git a/src/Structures/PingResults.cs b/src/Structures/PingResults.cs index baa0280..894ba40 100644 --- a/src/Structures/PingResults.cs +++ b/src/Structures/PingResults.cs @@ -28,14 +28,19 @@ public class PingResults public ulong GoodPackets { get; private set; } // Number of good replies received public ulong OtherPackets { get; private set; } // Number of other packet types received public bool HasOverflowed { get; set; } // Specifies if any of the results have overflowed - public bool ScanWasCanceled { get; set; } // Whether the scan was canceled early + public bool ScanWasCancelled { get; set; } // Whether the scan was canceled early private readonly Stopwatch _operationTimer = new Stopwatch(); // Used to time total time spent doing operation private double _responseTimeSum = 0; // Sum of all reply times (used to work out general average - public PingResults() + public PingResults() => Reset(); + + public void Reset() { // Default properties + StartTime = DateTime.MinValue; + EndTime = DateTime.MinValue; + Sent = 0; Received = 0; Lost = 0; @@ -48,6 +53,7 @@ public PingResults() OtherPackets = 0; HasOverflowed = false; + ScanWasCancelled = false; } public void Start() diff --git a/src/Utils/CommandLine.cs b/src/Utils/CommandLine.cs index 99a21e2..31dc7ad 100644 --- a/src/Utils/CommandLine.cs +++ b/src/Utils/CommandLine.cs @@ -48,7 +48,6 @@ public static bool Parse(string[] args, ref PingAttributes attributes, ref Displ case "-v": case "--v": ConsoleDisplay.Version(); - Helper.CheckRecentVersion(); if (displayConfig.RequireInput) { Helper.WaitForUserInput(); diff --git a/src/Utils/Helper.cs b/src/Utils/Helper.cs index a528029..51bc1fc 100644 --- a/src/Utils/Helper.cs +++ b/src/Utils/Helper.cs @@ -8,6 +8,7 @@ using System.Net; using System.Reflection; using System.Security.Cryptography; +using System.Text.Json; using System.Text.RegularExpressions; namespace PowerPing @@ -22,7 +23,6 @@ public static class Helper private static readonly string _ipv4Regex = @"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|$)){4}"; private static readonly string _urlRegex = @"[a-z0-9]+([\-\.]{1}[a-z0-9]+)*\.[a-z]{2,5}(:[0-9]{1,5})?"; private static readonly string _validScanRangeRegex = @"((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\.|\-|$)){5}"; - private static readonly string _githubReleaseVersionRegex = @"""(tag_name)"":""((\\""|[^""])*)"""; private static readonly double _stopwatchToTimeSpanTicksScale = (double)TimeSpan.TicksPerSecond / Stopwatch.Frequency; private static readonly double _timeSpanToStopwatchTicksScale = (double)Stopwatch.Frequency / TimeSpan.TicksPerSecond; @@ -86,7 +86,6 @@ public static bool IsBetween(long value, long left, long right) /// Produces cryprographically secure string of specified length /// /// - /// https://stackoverflow.com/a/1668371 /// public static String RandomString(int len = 11) { @@ -102,21 +101,10 @@ public static String RandomString(int len = 11) /// Produces cryprographically secure int of specified length /// /// - /// http://www.vcskicks.com/code-snippet/rng-int.php /// public static int RandomInt(int min, int max) { - int result; - - using (RandomNumberGenerator rng = new RNGCryptoServiceProvider()) - { - byte[] rngToken = new byte[4]; - rng.GetBytes(rngToken); - - result = BitConverter.ToInt32(rngToken, 0); - } - - return new Random(result).Next(min, max); + return RandomNumberGenerator.GetInt32(min, max); } /// @@ -191,48 +179,6 @@ public static ushort GenerateSessionId() return (ushort)(n ^ (n >> 16)); } - /// - /// Checks github api for latest release of PowerPing against current assembly version - /// Prints message to update if newer version has been released. - /// - /// - public static void CheckRecentVersion() - { - using (var webClient = new System.Net.WebClient()) - { - ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072; // TLS 1.2 - webClient.Headers["User-Agent"] = "PowerPing (version_check)"; // Need to specif a valid user agent for github api: https://stackoverflow.com/a/39912696 - - try - { - // Fetch latest release info from github api - string jsonResult = webClient.DownloadString( - $"http://api.github.com/repos/killeroo/powerping/releases/latest"); - - // Extract version from returned json - Regex regex = new Regex(_githubReleaseVersionRegex); - Match result = regex.Match(jsonResult); - if (result.Success) - { - string matchString = result.Value; - Version theirVersion = new Version(matchString.Split(':')[1].Replace("\"", string.Empty).Replace("v", string.Empty)); - Version ourVersion = Assembly.GetExecutingAssembly().GetName().Version; - - if (theirVersion > ourVersion) - { - Console.WriteLine(); - Console.WriteLine("========================================================="); - Console.WriteLine("A new version of PowerPing is available ({0})", theirVersion); - Console.WriteLine("Download the new version at: {0}", @"https://github.com/killeroo/powerping/releases/latest"); - Console.WriteLine("========================================================="); - Console.WriteLine(); - } - } - } - catch (Exception) { } // We just want to blanket catch any exception and silently continue - } - } - /// /// Split list into x equally sized lists /// @@ -309,7 +255,7 @@ public static string CheckForDuplicateFile(string filepath) string extension = Path.GetExtension(filepath); string? outDir = Path.GetDirectoryName(filepath); - string path = string.IsNullOrEmpty(outDir) ? Path.GetPathRoot(filepath) : outDir; + string? path = string.IsNullOrEmpty(outDir) ? Path.GetPathRoot(filepath) : outDir; string currentFilePath = filepath; bool goodFilename = false; @@ -321,7 +267,7 @@ public static string CheckForDuplicateFile(string filepath) if (File.Exists(currentFilePath)) { counter++; - currentFilePath = Path.Combine(path, $"{filename}({counter}){extension}"); + currentFilePath = Path.Combine(path ?? string.Empty, $"{filename}({counter}){extension}"); } else {